2009-08-09 97 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