explain
select
*
from
zipcode_distances z
inner join
venues v
on z.zipcode_to=v.zipcode
inner join
events e
on v.id=e.venue_id
where
z.zipcode_from='92108' and
z.distance <= 5
我正试图在5英里内的邮政编码92108找到所有“活动”,但是,我很难优化这个查询。
以下是解释的内容:
id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
1, SIMPLE, e, ALL, idx_venue_id, , , , 60024,
1, SIMPLE, v, eq_ref, PRIMARY,idx_zipcode, PRIMARY, 4, comedyworld.e.venue_id, 1,
1, SIMPLE, z, ref, idx_zip_from_distance,idx_zip_to_distance,idx_zip_from_to, idx_zip_from_to, 30, const,comedyworld.v.zipcode, 1, Using where; Using index
我正在“e”表上进行全表扫描,我无法弄清楚我需要创建哪个索引才能让它变快。
任何建议都将不胜感激
谢谢
答案 0 :(得分:8)
根据您问题中的EXPLAIN
输出,您已经拥有查询应使用的所有索引,即:
CREATE INDEX idx_zip_from_distance
ON zipcode_distances (zipcode_from, distance, zipcode_to);
CREATE INDEX idx_zipcode ON venues (zipcode, id);
CREATE INDEX idx_venue_id ON events (venue_id);
(我不确定你的索引名称idx_zip_from_distance
是否真的包含zipcode_to
列。如果没有,你应该添加它以使其成为covering index。而且,我'我们在venues.id
中包含idx_zipcode
列以确保完整性,但是,假设它是表格的主键并且您正在使用InnoDB,则无论如何都会自动包含它。)
然而,看起来MySQL正在选择一个不同的,可能是次优的查询计划,它会扫描所有事件,找到他们的场地和邮政编码,然后才能过滤距离上的结果。如果事件表的基数足够低,那么可以是最佳查询计划,但是从你提出这个问题的事实我认为不是。
次优查询计划的一个原因可能是太多索引,这会使计划程序混乱。例如,你真的是否需要zipcode表上的所有这三个索引,因为它存储的数据可能是对称的?就个人而言,我只建议我在上面描述的索引,加上一个唯一的索引(如果你没有人工的那个也可以是主键)(zipcode_to, zipcode_from)
(最好是按顺序,这样任何偶然的zipcode_to=?
查询都可以使用它。)
然而,基于我所做的一些测试,我怀疑MySQL选择错误的查询计划的主要问题仅仅取决于表的相对基数。据推测,你的实际zipcode_distances
表是巨大的,并且MySQL不够聪明,无法意识到WHERE
子句中的条件确实缩小了它的范围。
如果是这样,最简单的解决办法可能只是force MySQL to use the indexes you want:
select
*
from
zipcode_distances z
FORCE INDEX (idx_zip_from_distance)
inner join
venues v
FORCE INDEX (idx_zipcode)
on z.zipcode_to=v.zipcode
inner join
events e
FORCE INDEX (idx_venue_id)
on v.id=e.venue_id
where
z.zipcode_from='92108' and
z.distance <= 5
使用该查询,您确实应该获得所需的查询计划。 (这里确实需要FORCE INDEX
,因为只有USE INDEX
,查询规划者仍然可以决定使用表扫描而不是建议的索引,从而无法实现目的。当我第一次测试时,我就会发生这种情况。 )
答案 1 :(得分:1)
是否已为两个表中的列编制索引?
e.id and v.venue_id
如果不这样做,请在两个表中创建索引。如果您已经拥有,那么可能是您在一个或多个表中有少量记录,并且分析器检测到执行完整扫描而不是索引读取更有效。
答案 2 :(得分:0)
您可以使用子查询:
select * from zipcode_distances z, venues v, events e
where
z.id in (select id from zipcode z where z.zipcode_from='92108' and z.distance <= 5)
and z.zipcode_to=v.zipcode
and v.id=e.venue_id
答案 3 :(得分:-1)
您正在选择所有表(select *)
中的所有列,因此当查询引擎必须在每一行上从索引到表进行查找时,优化器中使用索引几乎没有意义。