MySQL索引,聯合索引,最左匹配原則的理解和總結

網上有很多文章講這個索引失效,最左匹配原則失效的,不能說他們說的不對,但卻是不夠全面的,如果拿網上大部分文章說的去面試的話,被面試官問多幾個情況就會矇住,以那些文章內的知識去根本不能做到舉一反三。

今天我這裏的是我個人實踐後對索引失效,聯合索引失效的總結

我使用的是MySQL5.6

目錄

索引

最左匹配原則

聯合索引

執行計劃Extra字段


索引

索引列上不要使用表達式

mysql 在使用不等於(!= 或者<>)的時候無法使用索引,會導致全表掃描

is null 、is not null 也無法使用索引

like以通配符開頭(’%abc…’),mysql索引會失效,會變成全表掃描的操作,不以通配符開頭時可以

字符串不加單引號索引失效

IN裏的數量少會使用索引,數量多不會使用。或者mysql認爲使用全表掃描要比使用索引快,數據太少或者查詢出來的結果很多的時候會出現

如果一個索引包含所有需要的查詢的字段的值,我們稱之爲覆蓋索引。覆蓋索引是非常有用的工具,能夠極大的提高性能。因爲,只需要讀取索引,而無需讀表,極大減少數據訪問量並且速度更快

如果一個where條件可能命中多個索引,那麼如果最終用上了索引,會使用最先創建的那個(與索引創建先後順序有關,而與key_len大小無關)

 

 

最左匹配原則

說到最左匹配原則肯定就要說聯合索引,那麼究竟什麼情況最左匹配原則會導致聯合索引失效

網上的文章一般都會說

如果索引了多列(聯合索引),要遵守最左前綴法則,指的是查詢從索引的最左前列開始並且不跳過索引中的列,尤其是索引的頭。就是最左優先,如果中間斷開了,索引不會用全,如果不含第一個字段那麼索引會失效

上面這種說法是不全面的!!注意!!如果不含第一個字段,當發生索引覆蓋時,仍然會使用索引,下面來實踐。

下圖是我的一張表,user表,不需要關心表結構,只需要關注我創建的這些爲了測試的單列索引或聯合索引

下圖可看到,where條件只有age,password,但確實符合索引覆蓋,select字段只有age和password。最終執行計劃顯示使用了u_a_p索引,從key_len可驗證出是計算了username,age,password三個字段的(由於我沒有放出表結構,這裏告訴大家是正確的)。

 

如果不是索引覆蓋呢?

下圖可見沒有使用索引

從下兩圖可見,當where出現了聯合索引的第一個字段的時候是遵循最左匹配原則的,中間斷開了不連續則索引不會用全,從key_len可知,並且不管是否是索引覆蓋都是如此

 

 

最左匹配聯合索引遇到like 通配符開頭'%...',則使用like的字段不使用索引,其餘如果符合可以,優化器會優化順序

使用OR,當發生索引覆蓋時,不管是否最左匹配,都會用到聯合索引並且是所有字段用上通過key_len可知,不存在用不全的情況。但是當不是索引覆蓋時,不會使用索引。下面實踐

下圖可見,where有兩個字段,key_len爲371

下圖所示,不管是否最左匹配,都會用到聯合索引並且是所有字段用上

下圖所示,當不是索引覆蓋時,不會使用索引。

 

聯合索引

使用聯合索引的好處。

  1. 減少開銷。建一個聯合索引(col1,col2,col3),實際相當於建了(col1),(col1,col2),(col1,col2,col3)三個索引。每多一個索引,都會增加寫操作的開銷和磁盤空間的開銷。對於大量數據的表,使用聯合索引會大大的減少開銷!
  2. 覆蓋索引。對聯合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那麼MySQL可以直接通過遍歷索引取得數據,而無需回表,這減少了很多的隨機io操作。減少io操作,特別的隨機io其實是dba主要的優化策略。所以,在真正的實際應用中,覆蓋索引是主要的提升性能的優化手段之一。
  3. 效率高。索引列越多,通過索引篩選出的數據越少。有1000W條數據的表,有如下sql:select from table where col1=1 and col2=2 and col3=3,假設假設每個條件可以篩選出10%的數據,如果只有單值索引,那麼通過該索引能篩選出1000W10%=100w條數據,然後再回表從100w條數據中找到符合col2=2 and col3= 3的數據,然後再排序,再分頁;如果是聯合索引,通過索引篩選出1000w10% 10% *10%=1w,效率提升可想而知!

 

 

執行計劃Extra字段

  • using index :使用覆蓋索引的時候就會出現
  • using where:在查找使用索引的情況下,需要回表去查詢所需的數據
  • using index condition:查找使用了索引,但是需要回表查詢數據 mysql5.6新增
  • using where;using index:查找使用了索引,但是需要的數據都在索引列中能找到,所以不需要回表查詢數據

using index condition官方解釋:

Index Condition Pushdown (ICP) is an optimization for the case where MySQL retrieves rows from a table using an index. Without ICP, the storage engine traverses the index to locate rows in the base table and returns them to the MySQL server which evaluates the WHERE condition for the rows. With ICP enabled, and if parts of the WHERE condition can be evaluated by using only columns from the index, the MySQL server pushes this part of the WHERE condition down to the storage engine. The storage engine then evaluates the pushed index condition by using the index entry and only if this is satisfied is the row read from the table. ICP can reduce the number of times the storage engine must access the base table and the number of times the MysQL server must access the storage engine.

存儲引擎通過使用索引條目來評估推送的索引條件,並且只有在滿足此條件的情況下,才從表中讀取行。 ICP可以減少存儲引擎必須訪問基表的次數以及MysQL服務器必須訪問存儲引擎的次數。

 

當使用了select * 或者含有某個字段不含在任何索引裏,即便where條件命中了索引,extra都是using index condition,只有發生索引覆蓋的時候纔是using where;using index,明顯using where;using index會優於using index condition,因爲不用回表

 

關於Extra這部分研究得還不夠深,歡迎大家交流

 

以上是我對索引,聯合索引,最左匹配原則的理解和總結,歡迎大家交流和指正錯誤的地方。非常建議大家親自去實踐,避免被一些文章誤導了。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章