具有连接的MySQL索引顺序

时间:2015-03-26 18:51:20

标签: mysql join indexing

我正在尝试正确设置索引中的列顺序,并且没有看到对此的直接答案。如果我们有类似以下的查询

SELECT ... all the things ... 
FROM tb_contact 
inner join tb_contact_association on tb_contact.id = tb_contact_association.attached_id 
where tb_contact_association.contact_id = '498' 
order by ... 

我们正在查看此联接的数据透视表tb_contact_association。如果不同时查看attach_id(在连接上)和contact_id(在哪里),就不会真正查询此表。

为tb_contact_association创建索引时,索引是否应该按顺序覆盖“attached_id,contact_id”?随着加入第一,然后在哪里?或者相反?或者他们每个人都单独?

感谢。

3 个答案:

答案 0 :(得分:2)

通常,索引中字段的顺序无关紧要, IF 使用相应的字段。

e.g。对于像这样的查询:

SELECT .. WHERE f1 = 'a' AND f2 = 'b' AND f3 = 'c'

INDEX(f3, f2, f1) - index can be used
INDEX(f1, f3, f1) - can be used
INDEX(f1, f2, f3) - can be used
INDEX(f1, f3) - completely usable
INDEX(f3, f1) - completely usable
INDEX(f4, f1) - cannot be used - no 'f4' field in the where clause
INDEX(f1, f4) - can be used, because 'f1' is in the where clause, but f4
    component will be ignored

WHERE子句的实际排序无关紧要。 WHERE f1 = 'a' AND f2 = 'b' v.s.就查询编译器/优化器而言,WHERE f2 = 'b' AND f1 = 'a'都是默认的。

答案 1 :(得分:1)

最有可能的是,这两个字段都应该有一个索引。但是在这个查询中,只有contact_id需要一个索引,Nathan的答案在更多细节中解释了原因。

特定查询的最佳索引是(contact_id,attached_id)。

答案 2 :(得分:1)

所需的索引取决于连接的运行方向。您可以通过在select语句上运行EXPLAIN来确定这一点。但在这种情况下,由于您的WHERE子句在tb_contact_association表上进行过滤,因此优化器很可能从此表开始并加入tb_contact表。

与tb_contact_association相比,如果tb_contact很小(几行),则会出现异常。要了解为什么会出现这种情况,请考虑一个极端的例子。如果tb_contact只有一行长,那么从该行开始显然会更快,加入tb_contact_association表中的相应行,并测试其contact_id的值,而不是通过整个更大的tb_contact_association表寻找contact_id = 498(即使有索引),然后加入tb_contact表。

但是,对于任何普通表,上面的查询将以tb_contact_association开头。对于加入,您需要在加入的列上添加索引。在这种情况下,那是tb_contact.id。您还需要一个索引来帮助您的WHERE子句,即在tb_contact_association.contact_id上。

对于此特定查询,您实际上并不需要tb_contact_association.attached_id的索引,只要该连接始终按照我们期望的方向进行即可。 tb_contact_association上的(contact_id,attached_id)(按此顺序)的复合索引应该是一个小帮助,因为它将允许直接从索引中提取该表的所有必要信息,从而保存每行的数据表读取。 (添加此索引后,您应该在查询EXPLAIN的额外部分中看到"使用索引")contact_id列用于WHERE子句,就像该列上的单个索引一样,但是在复合索引中,它可以直接从索引读取attachment_id,而不是从表中读取。