結合B+樹,談資料庫的聯合索引
先給一個問題:
資料庫表T有A,B,C三個欄位,對其建立聯合索引uniq(A,B,C),請問如下查詢哪些會用到索引?
1. SELECT * FROM T WHERE A=a AND B=b AND C=c;
2. SELECT * FROM T WHERE A=a AND B=b;
3. SELECT * FROM T WHERE A=a AND C=c;
4. SELECT * FROM T WHERE B=b AND C=c;
大家都知道聯合索引有最左原則。也就是說,如果聯合索引的第一個列沒有在WHERE語句中,或者所查詢的列其中並沒有在索引中被建立。那麼,這個聯合索引是無效的。
比如,上面的問題,這個索引可以被用於搜尋如下所示的資料列組合:
A,B,C
A,B
A
MySQL不能利用這個索引來搜尋沒有包含在最左字首的內容。例如,如果你按照B或C來搜尋,就不會使用到這個索引。
如果你搜索給定的A和C的組合,該索引也是不能用於這種組合值的,儘管MySQL可以利用索引來查詢匹配的A從而縮小搜尋的範圍。
那麼,為什麼是最左原則呢?
就要想想聯合查詢的結構是怎樣的。
首先,先看看B+樹的結構圖。
(圖源張洋的《MySQL索引背後的資料結構及演算法原理》一文)
那聯合索引呢?
這是一張表格,col1 是主建,col2和col3 是普通欄位。
(圖源張洋的《MySQL索引背後的資料結構及演算法原理》一文)
那麼,多列的索引是這樣的
(圖源張洋的《MySQL索引背後的資料結構及演算法原理》一文)
也就是說,聯合索引(col1, col2, col3)也是一棵B+樹,其非葉子節點儲存的是第一個關鍵字的索引,而葉子節點儲存的則是三個關鍵字col1、col2、col3三個關鍵字的資料,且按照col1-col2-col3的順序進行排序。
索引還可以這麼畫。
如果執行的是,SELECT * FROM T WHERE B=‘Tom’ AND C=4567;
那麼無法使用索引,因為索引是用A欄位先排序的,如果沒有先確定A,直接查詢B和C,那麼將會是全表查詢。
如果執行的是,SELECT * FROM T WHERE A=‘30’ AND B=Demi;
那麼,會先找到A欄位,再在A等於30的資料中(比如有很多條),找B等於Demi的資料。這樣是可以用到索引的。
如果執行的是,SELECT * FROM T WHERE A=‘18’ AND C=1234;
那麼,A欄位可以索引,而C不能索引。所以可以部分索引,也比全表查詢快。
現在,大概瞭解了什麼為什麼是最左原則。因為,B+樹是按照最左邊的欄位以此構建的。
PS:感謝貝貝網面試官提出的問題,並給出了建議。歡迎大家指正:)