复合索引中的单独连接子句

时间:2012-10-31 18:27:56

标签: mysql composite-index

复合指数是否有利于这样的事情:

SELECT * FROM a INNER JOIN b ON(a.id=b.id)
                INNER JOIN c ON(a.bar=c.id)
                INNER JOIN d ON(a.foo=d.id)

索引将是:

(a.id, a.bar, a.foo)

2 个答案:

答案 0 :(得分:3)

仅使用索引的前沿(a.id),因此只有INNER JOINb才能从索引中受益...所以索引中的其他列(a.bara.foo)在发布的示例查询中无益。

From the MySql documentation

  

如果列不支持,则MySQL无法使用索引执行查找   形成索引的最左前缀。假设你有SELECT   这里显示的陈述:

SELECT * 
FROM tbl_name 
WHERE col1=val1; 

SELECT * 
FROM tbl_name 
WHERE col1=val1 AND col2=val2;

SELECT * 
FROM tbl_name 
WHERE col2=val2; 

SELECT * 
FROM tbl_name 
WHERE col2=val2 AND col3=val3; 
     

如果(col1, col2, col3)上存在索引,   只有前两个查询使用索引。第三和第四个查询   确实涉及索引列,但(col2)(col2, col3)不是   最左边的(col1, col2, col3)前缀。

答案 1 :(得分:0)

JOINing(即INNER JOIN,而不是LEFT JOIN)时,优化程序将选择表中的 any 作为“第一”表。然后它将使用ON子句移至下一个表,并执行“ NLJ”(嵌套循环连接)以进入第二个表。等等

通常,当有一个WHERE子句(或某些其他事物)时,它将确定哪个表是“第一”。否则,优化器将通常选择最小的表。

鉴于其中一张表上的WHERE子句,它将寻找要使用的“最佳” INDEX。这样的索引很可能在WHERE子句中包含一个或多个列。单个表将不会同时使用两个索引(极少数例外)。

前进到“下一个”表时,可能ON子句中的列上的索引确定了最佳索引。请注意,如果您有ON a.x=b.x AND a.y=b.y,则最好使用复合INDEX(x,y)(两种顺序)。

回到不决定从哪个表开始的情况下……优化器将尝试对该表进行各种排序。每个不同的顺序都有一组不同的索引。

为此

     FROM a 
     INNER JOIN b ON(a.id=b.id)
     INNER JOIN c ON(a.bar=c.id)
     INNER JOIN d ON(a.foo=d.id)

这些是最佳选择,但我们不一定能预测将使用哪种:

a:  (id)  -- if coming from b
a:  (bar) -- if coming from c
a:  (foo) -- if coming from d
b:  (id)  -- if coming from b 
c:  (id)  -- if coming from a
d:  (id)  -- if coming from a

注意:每个表中可能已经有PRIMARY KEY(id),因此无需添加INDEX(id)

您说的是SELECT *,这意味着您需要所有四个表中的所有列。如果情况并非如此,我们可以讨论另一个优化:“覆盖索引”。

更多讨论:http://mysql.rjweb.org/doc.php/index_cookbook_mysql