面試官:(a,b,c)組合索引,查詢語句select...from...where a=.. and c=..走索引嗎應聘者:
-
最佳左字首法,如果索引了多列,要遵守最左字首法則,否則索引失效
-
按最左字首原則,a能走索引,c走不了,只能用到a部分索引
接下來,我們具體來分析一下
1、組合索引在樹中是如何排序的
在MySQL中建立聯合索引時會遵守最左字首匹配原則,即最左優先。要想理解聯合索引的最左匹配原則,先來理解下索引的底層原理。索引的底層是一顆B+樹,那麼聯合索引的底層也就是一顆B+樹,只不過聯合索引的B+樹節點中儲存的是鍵值。由於構建一棵B+樹只能根據一個值來確定索引關係,所以資料庫依賴聯合索引最左的欄位來構建。
舉個例子:建立一個(a,b)的聯合索引,那麼它的索引樹就是下圖的樣子。
可以看到a的值是有順序的:1,1,2,2,3,3,而b的值是沒有順序的1,2,1,4,1,2。但是我們又可發現a在等值的情況下,b值又是按順序排列的,但是這種順序是相對的。這是因為MySQL建立聯合索引的規則是首先會對聯合索引的最左邊第一個欄位排序,在第一個欄位的排序基礎上,然後在對第二個欄位進行排序,所以b=2這種查詢條件沒有辦法利用索引。
2、真實案例分析
我們來建立一張使用者表,在user_name,age,user_sex上建立組合索引
按照最左原則,我們按以下方式查詢資料:
通過觀察上面的結果圖可知,where後面的查詢條件,不論是使用(user_name)、(user_name,age) 還是 (user_name,age,user_sex),在查詢時都使用到了聯合索引。
那我們打亂查詢的順序,又會是什麼效果呢?
由上圖可知,即便我們打亂了查詢順序,仍然可以使用到索引,這是因為MySQL中有查詢優化器explain,所以sql語句中欄位的順序不需要和聯合索引定義的欄位順序相同,查詢優化器會判斷糾正這條SQL語句以什麼樣的順序執行效率高,最後才能生成真正的執行計劃,所以不論以何種順序都可使用到聯合索引。
接下來我們再來看問題的場景:
由上圖可知,我們也用到了索引,但是隻用了部分索引,也就是user_name部分的索引,還可以從另外一個欄位ref看到,使用的常量const只有一個。聯合索引樹是按照user_name欄位建立的,但user_sex相對於user_name來說是無序的,只有user_name是有序的,所以只能使用聯合索引中的user_name索引。
接下來我們再來看因為不滿足最左原則導致的索引失效場景:
由上圖可知,因為不滿足最左原則,本來要以user_name排序開始,現在user_name斷層了,沒辦法使用後面的索引了,故變成全表掃描了。
那我們有什麼辦法可以解決這種失效問題呢?
由上圖可知,我們查詢的不是全表欄位,而是索引欄位,通過觀察發現上面key欄位在搜尋中也使用了idx_user_nameAgeSex索引,可能許多同學就會疑惑它並沒有遵守最左匹配原則,按道理會索引失效,為什麼也使用到了聯合索引?因為沒有從age始匹配,且age單獨來說是無序的,所以它確實不遵循最左匹配原則,然而從type欄位可知,它雖然使用了聯合索引,但是它是對整個索引樹進行了掃描,正好匹配到該索引,與最左匹配原則無關,一般只要是某聯合索引的一部分,但又不遵循最左匹配原則時,都可能會採用index型別的方式掃描,但它的效率遠不如最做匹配原則的查詢效率高,index型別型別的掃描方式是從索引第一個欄位一個一個的查詢,直到找到符合的某個索引,與all不同的是,index是對所有索引樹進行掃描,而all是對整個磁碟的資料進行全表掃描。