【mysql 5.7】最左原則 & like查詢%在前為什麼不走索引
文章目錄
1. 問題的引入
大家Mysql索引有最左原則,所以通過 like '%XX%
'查詢的時候會造成索引失效(5.7版本覆蓋索引可以走索引),一般採用like 'XX%
'右邊匹配的方式來索引。
但是這樣一定會使用索引嗎?
答案是否定的,不一定會用。
1.1 驗證
建立實驗用的SQL:
CREATE TABLE `user` ( `ID_` BIGINT(20) NOT NULL AUTO_INCREMENT, `AGE_` INT(11) DEFAULT NULL, `NAME_` VARCHAR(255) DEFAULT NULL, PRIMARY KEY (`ID_`), UNIQUE KEY `NAME_` (`NAME_`) ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 #插入三條資料 INSERT INTO `user` VALUES ('1', '1', '測試1.1'), ('2', '2', '測試2.2'), ('3', '3', '測試3');
注意:下面3個例子是基於非覆蓋索引場景下
1.1.1 案例1 like ‘%測試%’
EXPLAIN select * from user where NAME_ like '%測試';
EXPLAIN結果如下:type=ALL,key=null,說明全表掃描沒有使用索引:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra ------ ----------- ------ ---------- ------ ------------- ------ ------- ------ ------ -------- ------------- 1 SIMPLE user (NULL) ALL (NULL) (NULL) (NULL) (NULL) 3 33.33 Using where
1.1.2 案例2 like ‘測試%’
EXPLAIN select * from user where NAME_ like '測試%';
EXPLAIN結果如下:type=ALL,key=null,rows=3檢索出所有資料,說明全表掃描沒有使用索引:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra ------ ----------- ------ ---------- ------ ------------- ------ ------- ------ ------ -------- ------------- 1 SIMPLE user (NULL) ALL NAME_ (NULL) (NULL) (NULL) 3 100.00 Using where
1.1.3 案例3 like ‘測試1%’
EXPLAIN select * from user where NAME_ like '測試1%';
EXPLAIN結果如下:type=range,key=NAME_,rows=1檢索出一條資料,說明使用了索引:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
------ ----------- ------ ---------- ------ ------------- ------ ------- ------ ------ -------- -----------------------
1 SIMPLE user (NULL) range NAME_ NAME_ 1023 (NULL) 1 100.00 Using index condition
1.2 總結
從上面三個案例可以看出,like ‘xxxx%’ 時不一定100%使用索引,是否使用索引與該條件數量和資料總量比例有關
2. 非覆蓋索引場景下為什麼%在前為什麼不走索引
%在前的例子:
SELECT * FROM xttblog WHERE name like '%xttblog';
說到這個例子,估計很多人會提到最左匹配原則。那麼為什麼要搞一個最左匹配原則呢?為什麼不搞一個最右匹配原則?
這個問題,其實是和 B+Tree 有些關係,索引樹從左到右都是有順序的。對於索引中的關鍵字進行對比的時候,一定是從左往右以此對比,且不可跳過。
為什麼是最左匹配原則?這個其實很好理解。比如,我們要比較一個字串。xttblog
與 xmtblog
,我們肯定是先從第一個字元開始比較吧,第一個相同後,再比較第二個字元,以此類推。所以要從左邊開始,並且是不能跳過的。SQL 索引也是這樣的。
然後,我們再來看標題中的問題。% 在前,就代表,我前面的內容不確定。不確定,我們怎麼比較?只能一個一個的比較,那就相當於,全匹配了,全匹配就不需要索引,還不如直接全表掃描。
在關鍵字比較的時候,會把字串轉換成 ascll 碼,如 abc 變成 97 98 99,然後從左往右一個字元一個字元進行對比。like %xttblog 這個怪物,因為 % 表示全匹配,所以 MySQL 就放棄索引了,進行全表掃描。
問題的根因
問題的引出