軟件版本mysql5.7
根據官網的文檔 https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html
查詢條件要符合最左原則才能使用到索引
首先說說聯合索引的好處:
覆蓋索引,這一點是最重要的,重所周知非主鍵索引會先查到主鍵索引的值再從主鍵索引上拿到想要的值,這樣多一次查詢索引下推。但是覆蓋索引可以直接在非主鍵索引上拿到相應的值,減少一次查詢。
在一張大表中如果有 (a,b,c)聯合索引就等於同時加上了 (a) (ab) (abc) 三個索引減少了存儲上的一部分的開銷和操作開銷
梯度漏斗,比如 select *from t where a = 1 and b = 2 and c = 3; 就等於在滿足 a = 1 的一部分數據中過濾掉b = 2 的 再從 a = 1 and b = 2 過濾掉 c = 3 的,越多查詢越高效。
到底啥是最左原則?
即最左優先,在檢索數據時從聯合索引的最左邊開始匹配,類似於給(a,b,c)這三個字段加上聯合索引就等於同時加上了 (a) (ab) (abc) 這三種組合的查詢優化
舉個栗子:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(25), `sex` varchar(25) , `city` varchar(25) , PRIMARY KEY (`id`) USING BTREE, INDEX `name`(`name`, `sex`, `city`) USING BTREE )
EXPLAIN select * from `user` where sex='';
這樣是無法觸發聯合索引的,因為不符合最左原則,沒有命中(a) (ab) (abc) 這種組合
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | user | NULL | index | NULL | name | 309 | NULL | 3 | 33.33 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
1 row in set (0.02 sec)
另外使用執行計划一定要看結果,只有possible_keys有值的情況下才是命中索引
還有一點就是where條件的順序是否會影響索引的命中,就是本來(ab)的組合,故意寫where語句時寫成(ba),答案是沒有影響,只要遵循了索引的最左原則即可,至少在mysql5.7測試沒有問題。
最后,談談索引的底層數據結構b+tree
我們知道BTREE 每個節點都是一個二元數組: [key, data],所有節點都可以存儲數據。key為索引key,data為除key之外的數據。
查找算法:首先從根節點進行二分查找,如果找到則返回對應節點的data,否則對相應區間的指針指向的節點遞歸進行查找,直到找到節點或未找到節點返回空指針
B+Tree有以下不同點:非葉子節點不存儲data,只存儲索引key;只有葉子節點才存儲data,而Mysql中B+Tree:在經典B+Tree的基礎上進行了優化,增加了順序訪問指針。在B+Tree的每個葉子節點增加一個指向相鄰葉子節點的指針,就形成了帶有順序訪問指針的B+Tree。這樣就提高了區間訪問性能:請見下圖,如果要查詢key為從18到49的所有數據記錄,當找到18后,只需順着節點和指針順序遍歷即可

