2016-11-17 61 views
0

我正在使用MySQL 5.6,并且在某些非常大的表中遇到了一些查询性能问题。具体而言,我不确定如何在表格之间同时存在引用以及in()条件时正确索引表格。使用外键和范围进行查询的索引设计

简化表如下所示(A和B都是巨大的表,而C是一个小桌子与大约20行,所有的表是InnoDB的)

(ID INT,创建日期时间,VAL INT)

(ID INT,A_ID INT,C_ID INT)

ç(ID INT,VAL INT)

查询有问题看起来是这样的:

Select a.id 
    from a 
    join b ON (a.id = b.a_id) 
    where a.created >= now() - interval 90 day 
     and a.val = 0 
     and b.c_id in (
     SELECT id 
      from c 
      where val = 1) 

我已经创建了一个索引为(VAL,创建ID),一个在B中(C_ID,A_ID),它的伟大工程时,有一个“ ='condition on c_id(例如,c_id = 5)但是使用'in()'条件解释告诉我,我的A上的索引没有被使用,而是使用主键索引,并且此查询正在永久。强制使用我的索引似乎也没有帮助。

有关如何更好地索引此索引或以其他方式提高此类查询性能的任何提示或想法?

回答

1

IN (SELECT ...)效率低于JOIN

Select a.id 
    from a 
    join b ON (a.id = b.a_id) 
    JOIN c ON b.c_id = c.id 
    where a.created >= now() - interval 90 day 
     and a.val = 0 
     and c.val = 1 

指标:

A: INDEX(val, created) -- in that order 
B: INDEX(a_id, c_id) -- in that order; "covering" 
C: Nothing new needed, assuming you have PRIMARY KEY(id) and InnoDB 

(编辑)的索引假设表将在这个顺序进行:A,B,C这很可能就会因为... A可能在WHERE中具有最好的选择性。很明显,B,然后C接下来。因此,我对B索引的排序。

假设A的PK是(id),那么INDEX(val, created)INDEX(val, created, id)(如您所建议的)完全相同。

随着一个“衍生的”表的配方中,优化器“必须”与C开始,然后转移到B,最后,A

C: INDEX(val, id)  -- (again, `id` optional) 
B: INDEX(c_id, a_id) -- as you stated 
A: Given that it has `PRIMARY KEY(id)` and is InnoDB, no index is useful. 

由于滤波的无力上a.val的和a.created,我预测,即使这个提法将是比我慢:

Select a.id 
    FROM (SELECT id FROM C WHERE val = 1) AS cx 
    JOIN B ON b.c_id = cx.id 
    JOIN A ON (a.id = b.a_id) 
    where a.created >= now() - interval 90 day 
     and a.val = 0 

Index Cookbook。如果B是许多映射表,那么请特别注意该主题的部分。

+0

非常感谢您的帮助。看起来优化器并不总是在同一页面上,但它涉及到要使用哪个索引。使用这些新索引,查询运行速度要快得多,但是我必须明确告诉它使用它们,否则它仍会尝试使用主键在需要年龄的A上。 –