1. 程式人生 > 資料庫 >【mysql 5.7】最左原則 & like查詢%在前為什麼不走索引

【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 有些關係,索引樹從左到右都是有順序的。對於索引中的關鍵字進行對比的時候,一定是從左往右以此對比,且不可跳過。

為什麼是最左匹配原則?這個其實很好理解。比如,我們要比較一個字串。xttblogxmtblog,我們肯定是先從第一個字元開始比較吧,第一個相同後,再比較第二個字元,以此類推。所以要從左邊開始,並且是不能跳過的。SQL 索引也是這樣的。

然後,我們再來看標題中的問題。% 在前,就代表,我前面的內容不確定。不確定,我們怎麼比較?只能一個一個的比較,那就相當於,全匹配了,全匹配就不需要索引,還不如直接全表掃描。

在這裡插入圖片描述
在關鍵字比較的時候,會把字串轉換成 ascll 碼,如 abc 變成 97 98 99,然後從左往右一個字元一個字元進行對比。like %xttblog 這個怪物,因為 % 表示全匹配,所以 MySQL 就放棄索引了,進行全表掃描。





問題的根因
問題的引出