2009-08-09 68 views
29

这是一个我永远拥有的问题。MySQL索引和订单

据我所知,指数的顺序很重要。所以像[first_name, last_name]这样的索引与[last_name, first_name]不一样吧?

如果我只定义了第一个指数,它意味着它将只用于

SELECT * FROM table WHERE first_name="john" AND last_name="doe"; 

而不是

SELECT * FROM table WHERE last_name="doe" AND first_name="john"; 

由于我使用的是ORM,我在不知道这些命令将命令这些列将被调用。这是否意味着我必须在所有排列上添加索引?如果我有2列索引,这是可行的,但如果我的索引是3列或4列,会发生什么?

回答

44

当您的查询条件仅适用于索引的PART时,索引顺序很重要。试想一下:

  1. SELECT * FROM table WHERE first_name="john" AND last_name="doe"

  2. SELECT * FROM table WHERE first_name="john"

  3. SELECT * FROM table WHERE last_name="doe"

如果你的指数是(first_namelast_name)查询1和2将使用它,查询#3韩元“T。 如果您的索引是(last_namefirst_name)查询1和3将使用它,则查询#2不会。在这两种情况下,更改WHERE子句中的条件顺序都不起作用。

详情here

更新
如果上面没有明确的 - 如果在查询条件中的列构成索引的最左前缀的MySQL只能使用一个索引。上面的查询#2不能使用(last_name,first_name)索引,因为它仅基于first_namefirst_name不是(last_name,first_name)索引的最左边前缀。

查询中的条件顺序无关紧要;上面的查询#1将能够使用(last_name,first_name)索引,因为它的条件是first_namelast_name,并且它们一起构成最左边的前缀(last_name,first_name)索引。

+0

所以我猜SELECT * FROM table WHERE last_name =“doe”AND first_name =“john”不会? 如果是这样的话,那么因为所有的查询建筑物都被我的ORM隐藏起来了,所以我可能必须定义2个索引...真的很糟糕,因为我有3列的索引来定义...... – 2009-08-09 21:11:34

+1

不,你误会了。 WHERE'last_name' =“doe”AND'first_name' =“john”查询可以使用('first_name','last_name')或('last_name','first_name')索引。 – ChssPly76 2009-08-09 21:22:07

+0

一个问题:对于具有2 AND条件的查询,它是否重要,速度明智,它的索引与查询中的条件相比是否“反向”,或者取决于这些列的基数? – Mihai 2014-11-12 21:52:25

5

ChssPly76是正确的,布尔表达式的顺序不必匹配索引中列的顺序。布尔运算符是commutative,MySQL优化器足够聪明,可以知道如何在大多数情况下将表达式与索引匹配。

我还想补充一点,您应该学习如何使用MySQL的EXPLAIN功能,以便您自己可以看到优化程序将为给定查询选择哪些索引。

+2

+1解释。 – Petrogad 2010-11-08 16:16:27

+0

MySQL工作台显示了'执行计划'下'EXPLAIN'信息的图形表示。 – 2016-04-07 18:28:34

2

为什么不把答案稍微延长一点,让所有的东西都一目了然。

如果表具有多列索引,则优化器可以使用该索引的任何最左边的前缀来查找行。例如,如果您在(col1, col2, col3)上有三列索引,则您具有(col1),(col1, col2)(col1, col2, col3)的索引搜索功能。

如果列不构成索引的最左侧前缀,那么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)。 - MySQL dev