1. 程式人生 > 其它 >MySQL 不走索引的情況

MySQL 不走索引的情況

技術標籤:MySQL優化mysql資料庫sql

文章目錄

表資訊

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查詢時,以%開頭不走索引。