具有外键和范围的查询的索引设计

时间:2016-11-17 10:26:30

标签: mysql sql indexing innodb

我正在使用MySQL 5.6,并且在一些非常大的表中遇到查询性能方面的问题。具体来说,当表和表之间存在引用以及in()条件时,我不确定如何正确索引表。

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

A (id int,created datetime,val int)

B (id int,a_id int,c_id int)

C (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 ) 

我在A上创建了一个索引(val,created,id),在B上创建了一个索引(c_id,a_id),当c_id上有一个'='条件(例如c_id = 5)时效果很好但是在'in()'条件下,解释告诉我我的A上的索引没有被使用,而是使用主键索引,这个查询将永远消失。强制使用我的索引似乎也没有帮助。

有关如何更好地对此进行索引或提高此类查询性能的任何提示或想法?

1 个答案:

答案 0 :(得分: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可能在{{1}中具有最佳选择性}}。显然,WHERE,接着是B。因此,我对C的索引进行了排序。

假设A的PK为B,则(id)INDEX(val, created)相同(正如您所建议的那样)。

使用'派生'表格配方,优化器必须'从INDEX(val, created, id)开始,然后转到C,最后转到B

A

由于无法过滤a.val和a.created,我预测即使这个公式也会比我的慢:

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.

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