Mysql聯合索引最左匹配原則
今天面試時,遇到一個面試官,問我的資料庫問題,其中有一個就是涉及根本的mysql的最左匹配原則問題,當問我聯合主鍵的第二三欄位,單獨查詢時,是否走索引,我說的是可以,他當時笑了,我的回答沒有回答的那麼嚴謹,所以面試過後整理了一下。也為了以後自己能回答的更漂亮完美。
我們都知道Mysql資料庫的最左字首原則。
比如有如下表,表有三個欄位a,b,c
table
a | b | c |
現在我建立了一個聯合唯一索引:`index_a_b_c` (a,b,c)
那麼按照最左字首匹配原則:我在查詢條件中,如下情況都能用到索引:
(1)select * from table where a = 1 (2)select * from table where a = 1 and b =1 (3)select * from table where a = 1 and b =1 and c= 1 (4)select * from table where a = 1 and c= 1
此時我們可以藉助mysql查詢優化器explain,explain會糾正sql語句該以什麼樣的順序執行效率最高,最後才生成真正的執行計劃。
為什麼要使用聯合索引
減少開銷。建一個聯合索引(a,b,c),實際相當於建了(a),(a,b),(a,b,c)三個索引。每多一個索引,都會增加寫操作的開銷和磁碟空間的開銷。對於大量資料的表,使用聯合索引會大大的減少開銷!
覆蓋索引。對聯合索引(a,b,c),如果有如下的sql: select col1,col2,col3 from test where a=1 and b=2。那麼MySQL可以直接通過遍歷索引取得資料,而無需回表,這減少了很多的隨機io操作。減少io操作,特別的隨機io其實是dba主要的優化策略。所以,在真正的實際應用中,覆蓋索引是主要的提升效能的優化手段之一。
效率高。索引列越多,通過索引篩選出的資料越少。有1000W條資料的表,有如下sql:select from table where a=1 and b=2 and c=3,假設假設每個條件可以篩選出10%的資料,如果只有單值索引,那麼通過該索引能篩選出1000W10%=100w條資料,然後再回表從100w條資料中找到符合col2=2 and col3= 3的資料,然後再排序,再分頁;如果是聯合索引,通過索引篩選出1000w10% 10% *10%=1w,效率提升可想而知!
引申
對於聯合索引(a,b,c),查詢語句SELECT * FROM test WHERE b=2;
是否能夠觸發索引?
大多數人都會說NO,實際上卻是YES。
原因:
1 2 |
EXPLAIN SELECT * FROM test WHERE b=2;
EXPLAIN SELECT * FROM test WHERE a=1;
|
觀察上述兩個explain結果中的type欄位。查詢中分別是:
- type: index
- type: ref
index:這種型別表示mysql會對整個該索引進行掃描。要想用到這種型別的索引,對這個索引並無特別要求,只要是索引,或者某個聯合索引的一部分,mysql都可能會採用index型別的方式掃描。但是呢,缺點是效率不高,mysql會從索引中的第一個資料一個個的查詢到最後一個數據,直到找到符合判斷條件的某個索引。所以,上述語句會觸發索引。
ref:這種型別表示mysql會根據特定的演算法快速查詢到某個符合條件的索引,而不是會對索引中每一個數據都進行一一的掃描判斷,也就是所謂你平常理解的使用索引查詢會更快的取出資料。而要想實現這種查詢,索引卻是有要求的,要實現這種能快速查詢的演算法,索引就要滿足特定的資料結構。簡單說,也就是索引欄位的資料必須是有序的,才能實現這種型別的查詢,才能利用到索引。
總結:以上我們可以得出,不要硬拿最左匹配原則去實際運用,比如explain中type為index型別的特殊情況。所以沒有那麼絕對。
作者:SpringWater
出處:https://www.cnblogs.com/springwater/
本部落格所有文章僅用於學習、研究和交流目的,歡迎非商業性質轉載。
博主的文章沒有高度、深度和廣度,只是湊字數。由於博主的水平不高,不足和錯誤之處在所難免,希望大家能夠批評指出。
博主是利用讀書、參考、引用、抄襲、複製和貼上等多種方式打造成自己的文章,請原諒博主成為一個無恥的文件搬運工!