1. 程式人生 > >索引——最左字首原則

索引——最左字首原則

1. 索引建立的原則

用於索引的最好的備選資料列是那些出現在WHERE子句、join子句、ORDER BY或GROUP BY子句中的列。

僅僅出現在SELECT關鍵字後面的輸出資料列列表中的資料列不是很好的備選列

SELECT
col_a <- 不是備選列
FROM
tbl1 LEFT JOIN tbl2
ON tbl1.col_b = tbl2.col_c <- 備選列
WHERE
col_d = expr; <- 備選列

當然,顯示的資料列與WHERE子句中使用的資料列也可能相同。
我們的觀點是輸出列表中的資料列本質上不是用於索引的很好的備選列。


2. 複合索引的建立以及最左字首原則

索引字串值的字首(prefixe)。如果你需要索引一個字串資料列,那麼最好在任何適當的情況下都應該指定字首長度。
例如,如果有CHAR(200)資料列,如果前面10個或20個字元都不同,就不要索引整個資料列。
索引前面10個或20個字元會節省大量的空間
你可以索引CHAR、VARCHAR、BINARY、VARBINARY、BLOB和TEXT資料列的字首。


假設你在表的state、city和zip資料列上建立了複合索引。索引中的資料行按照state/city/zip次序排列,
因此它們也會自動地按照state/city和state次序排列。這意味著,即使你在查詢中只指定了state值,
或者指定state和city值,MySQL也可以使用這個索引。因此,這個索引可以被用於搜尋如下所示的資料列組合:
state, city, zip
state, city
state

MySQL不能利用這個索引來搜尋沒有包含在最左字首的內容。例如,如果你按照city或zip來搜尋,
就不會使用到這個索引。如果你搜索給定的state和具體的ZIP程式碼(索引的1和3列),
該索引也是不能用於這種組合值的,儘管MySQL可以利用索引來查詢匹配的state從而縮小搜尋的範圍。

如果你考慮給已經索引過的表新增索引,那麼就要考慮你將增加的索引是否是已有的多列索引的最左字首。
如果是這樣的,不用增加索引,因為已經有了(例如,如果你在state、city和zip上建立了索引,那麼沒有必要再增加state的索引)。

3. 例項分析

通過例項理解單列索引、多列索引以及最左字首原則
例項:現在我們想查出滿足以下條件的使用者id:
mysql>SELECT `uid` FROM people WHERE lname`='Liu'  AND `fname`='Zhiqun' AND `age`=26
因為我們不想掃描整表,故考慮用索引。

單列索引:
ALTER TABLE people ADD INDEX lname (lname);
將lname列建索引,這樣就把範圍限制在lname='Liu'的結果集1上,之後掃描結果集1,產生滿足fname='Zhiqun'的結果集2,再掃描結果集2,找到 age=26的結果集3,即最終結果。

由於建立了lname列的索引,與執行表的完全掃描相比,效率提高了很多,但我們要求掃描的記錄數量仍舊遠遠超過了實際所需 要的。雖然我們可以刪除lname列上的索引,再建立fname或者age 列的索引,但是,不論在哪個列上建立索引搜尋效率仍舊相似。

多列索引:
ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);
為了提高搜尋效率,我們需要考慮運用多列索引,由於索引檔案以B-Tree格式儲存,所以我們不用掃描任何記錄,即可得到最終結果。

注:在mysql中執行查詢時,只能使用一個索引,如果我們在lname,fname,age上分別建索引,執行查詢時,只能使用一個索引,mysql會選擇一個最嚴格(獲得結果集記錄數最少)的索引。


3.最左字首:顧名思義,就是最左優先,上例中我們建立了lname_fname_age多列索引,相當於建立了(lname)單列索引,(lname,fname)組合索引以及(lname,fname,age)組合索引。


注:在建立多列索引時,要根據業務需求,where子句中使用最頻繁的一列放在最左邊。