MySQL 不走索引的情況
阿新 • • 發佈:2021-01-31
文章目錄
表資訊
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` varchar(20) DEFAULT NULL,
`b` int(20) DEFAULT NULL,
`c` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_a` (`a`) USING BTREE ,
KEY `idx_b` (`b`) USING BTREE,
KEY `idx_c` (`c`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
1 函式操作
select * from t1 where date(c) = '2021-01-30';
可見,這條sql並沒有走索引,而是全表掃描。
原因:對條件欄位做函式操作不會走索引。
因為MySQL中,普通索引是B+樹,其中儲存的是列的實際值和主鍵值,對欄位做函式操作後,無法定位到索引樹中的值,所以會放棄走索引。
優化
explain select * from t1 where c >= '2021-01-01 00:00:00' and c <= '2021-01-31 00:00:00';
去掉函式後,還是沒有走索引,這是為什麼?因為這個查詢範圍的資料量過大,導致不走索引,而是全表掃描。一般查詢資料量到總量的30%就不會走索引了。下面縮小下查詢範圍再試一下。
explain select * from t1 where c >= '2021-01-31 00:00:00' and c <= '2021-01-31 00:00:00';
2 隱式轉換
什麼時隱式轉換?
當操作符與不同型別的操作物件一起使用時,就會發生型別轉換以使操作相容。某些轉換是隱式的
關於隱式轉換的官方文件
explain select * from t1 where a = 1000; -- (a是varchar型別)
可以看到,可能走的索引有idx_a,但實際並沒有走,因為a是varchar型別,會做隱式轉換,實際上執行的是
explain select * from t1 where cast(a as signed int) = 1000;
這就回到了上一點,對索引欄位做函式操作時,會放棄走索引。
注意:
explain select * from t1 where b = '1000'; -- b為int型別
這個sql會走索引,因為MySQL會自動把字串轉為數值來進行比較。
3 模糊查詢
explain select * from t1 where a like '%10%';
模糊查詢時,如果以萬用字元開頭,就不會走索引。
4 範圍查詢
範圍查詢其實在第1點裡涉及過,如下sql不會走索引,因為查詢的資料範圍過大。
explain select * from t1 where c >= '2021-01-01 00:00:00' and c <= '2021-01-31 00:00:00';
優化器會根據檢索比例、表大小、I/O塊大小等進行評估是否使用索引。比如單次查詢的資料量過大,優化器將不走索引。
優化:降低單次查詢範圍,分多次查詢。
5 計算操作
explain select * from t1 where b-1 =1000;
原因:對索引欄位做計算操作,不會走索引。
優化
explain select * from t1 where b = 1000+1; -- 這只是舉例,實際不會有這麼笨的資料
6 總結
- 索引欄位不要做函式、計算的操作。
- 避免隱式轉換。
- 注意查詢範圍,不要過大。
- like查詢時,以%開頭不走索引。