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也帶上了)。