不知道大家有沒有聽過這麼一個江湖傳言:
“如果組合索引中包含的列,有範圍查詢,那麼它之後的列將不會走索引”。
本着“先問是不是,再問爲什麼”的原則,我們搞個試驗。
首先準備一個表“goods_detail”,主要字段:
tenant_id、buss_day、goods_id
我們創建一個組合索引:
KEY `idx_tbg` (`tenant_id`,`buss_day`,`goods_id`)
查詢語句SQL1:
SELECT
*
FROM
goods_detail
WHERE
tenant_id = '996'
AND buss_day BETWEEN "2020/1/1" AND "2020/1/6"
AND goods_id = '985';
執行計劃如下:
查詢語句SQL2:
SELECT
*
FROM
goods_detail
WHERE
tenant_id = '996'
AND buss_day IN ( "2020/1/1", "2020/1/2", "2020/1/3", "2020/1/4", "2020/1/5", "2020/1/6" )
AND goods_id = '985';
執行計劃如下:
從以上兩個執行計劃可以看出:buss_day使用in匹配比between匹配掃描的行數要低得多
原因就在於:SQL2的組合索引中goods_id列條件使用上了索引
爲何between不走索引,採用in後可以走索引
在探尋原因之前,需要先看下索引是如何在mysql中存儲的。
我們通常使用的innodb中,索引的數據結構是B+樹(樹高度低、效率高),有兩種索引:聚簇索引、二級索引
聚簇索引:所有完整的用戶記錄都存放在這個聚簇索引的葉子節點處,在InnoDB存儲引擎中,聚簇索引就是數據的存儲方式
二級索引:除聚簇索引之外的索引,由用戶自主創建,不包含完整的用戶記錄,只包含用戶設置的部分字段
聯合索引
用戶在創建二級索引時,可以選擇單個字段作爲索引,也可以選擇多個字段作爲索引。我們稱多個字段組成的索引爲組合索引(或聯合索引)
mysql在存儲聯合索引時:
- 先把各個記錄和頁按照從左往右第一列進行排序。
- 在記錄的前一列相同的情況下,採用下一列進行排序
- 依此類推
通過以上操作,保證了所有索引數據是按照索引列的值從小到大的順序排好序的。
當我們要查找匹配索引條件時,只需從左往右依次匹配。
分析下SQL1:
第一列:tenant_id 等值匹配,可以匹配到精確地索引
第二列:buss_day範圍匹配,匹配出來的buss_day具體有哪些,是不可以知的
第三列:由於匹配出來的buss_day不可知,goods_id無法走索引匹配
分析下SQL2:
第一列:tenant_id 等值匹配,可以匹配到精確地索引
第二列:buss_day等值匹配,匹配出來的buss_day是可知的
第三列:由於匹配出來的buss_day可知,goods_id走索引匹配
在組合索引中,除了使用了between匹配外,採用>、<、like等進行匹配都會導致後面的列無法走索引,因爲通過以上方式匹配到的數據是不可知的。
歡迎拍磚。。。