Mysql的聯合索引最左匹配原則小記

mysql的聯合索引,也稱爲組合索引,指的是建立一個索引的時候選擇多個字段。

可能我們都聽說過聯合索引的最左匹配原則,今天我們就這個主題實戰討論一下。

使用工具:navicat。

創建表:

我不喜歡上傳建表語句,那樣不直觀。

創建聯合索引,

ok,準備工作完成,讓我們以各種查詢姿勢來觀察下對應的查詢計劃。

1select * 系列

        select * 系列走普通索引需要回表操作,無法實現索引覆蓋。這裏順便講一下回表和索引覆蓋的概念,知道的請忽略下一段。

        在mysql的innodb引擎中,數據是掛在主鍵的葉子節點下的,而普通索引的葉子節點下面掛的是主鍵。所以當我們根據普通主鍵索引查詢出主鍵後,還需要再去主鍵索引樹上查找一遍才能獲取到數據,這就是回表。所以我們的select *查詢走普通索引的時候,都是需要回表的。那麼什麼是索引覆蓋呢,簡單來說就是select語句在一顆索引樹上就能獲取到所需的數據,不需要再去遍歷一遍別的索引樹,也就是說我們的select *改成了select xx(xx指的是索引),或者select * where走的不是普通索引,而是主鍵。總結來說,索引覆蓋就是不需要回表的情況。

ok,接下來上第一條sql語句:

因爲我們的索引最左邊是name列,所以毫無疑問的使用到了索引。

第二條sql,我們把查詢條件改爲索引的第二個字段試一試。

這樣會不會走索引呢?不會的,因爲按照最左匹配原則,mysql在查找聯合索引的時候會先比較第一個字段name,但我們的查詢條件沒有name,mysql就不知道咋辦了,只能全文搜索。如下圖。

 

第三條語句,

這條語句應該是我們最正常走聯合索引的情況,所以毫無疑問的,使用到了索引。

第四條,也是最容易迷惑的一條。

沒錯,我們把age 和 name 調換一下,看起來不符合最左前綴匹配,還能不能用到索引呢?

答案是肯定的,mysql這點邏輯還是處理的了的。

接下來,

2 select 索引上的字段

第一條,

  正常使用索引的情況,我們看下和select*有什麼區別。

        和上面的第三條比起來,我們發現多了個Using index,也就是說只需要在這棵索引樹上就可以取到所需數據,不需要回表,也就是實現了索引覆蓋。

第二條,

直接上explain,我們看下有什麼區別。

        可以看到,除了不需要回表,我們的索引檢索長度也由33減小到了28。這個好理解,因爲我們只需要查滿足name的條件,不需要再去檢索age這個條件,自然就變小了。

最後一條,也是非常迷惑的一條,這條要謹記,面試官可能會在這給你挖坑。

我們把where條件改成聯合索引的非最左字段。按道理講這樣就不會走索引了。但是請看結果。

看到沒,仍然使用到了索引。

爲什麼呢?很簡單,這個索引的使用方式就不是簡單的B+樹分叉搜索了,而是挨個查找,所以我們的rows檢索行數也就從正常走索引的1變成了7(我這裏只有七條數據),因爲mysql只需要遍歷一遍索引樹就可以找到數據了。所以這個地方我們一定要注意別被帶到坑裏去。

總結一下

1.聯合索引要使用最左前綴匹配,即最左邊的字段會建立單獨的索引,我們的sql語句where一定要包含這個字段才能用到索引。

2.走不走索引不知看where子句,還要看select的字段,有可能走索引,而且是非常慢的挨個遍歷(這種查詢效率依然很慢,大家不要這麼做,建議跟第一條一樣命中索引)。

3.聯合索引的檢索過程是先走最左邊的字段,然後再去找後面的字段。如索引(a,b,c),先去找a,找到後再去找b或者c.這時我們的查詢條件沒有b也沒關係,因爲只要找到了a,剩下的檢索量就很小了(除非你的數據中a有大量的重複值,這時候就需要把b也帶上了)。

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