數據庫字段明明有加索引,卻查詢效率這么低,教你避免采坑的五大方法


前提:數據准備

drop table if exists t1; /* 如果表t1存在則刪除表t1 */

CREATE TABLE `t1` ( /* 創建表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;

drop procedure if exists insert_t1; /* 如果存在存儲過程insert_t1,則刪除 */
delimiter ;;
create procedure insert_t1() /* 創建存儲過程insert_t1 */
begin
declare i int; /* 聲明變量i */
set i=1; /* 設置i的初始值為1 */
while(i<=10000)do /* 對滿足i<=10000的值進行while循環 */
insert into t1(a,b) values(i,i); /* 寫入表t1中a、b兩個字段,值都為i當前的值 */
set i=i+1; /* 將i加1 */
end while;
end;;
delimiter ;
call insert_t1(); /* 運行存儲過程insert_t1 */

update t1 set c = '2019-05-22 00:00:00'; /* 更新表t1的c字段,值都為'2019-05-22 00:00:00' */
update t1 set c = '2019-05-21 00:00:00' where id=10000; /* 將id為10000的行的c字段改為與其它行都不一樣的數據,以便后面實驗使用 */

1.要查詢測試表 t1 單獨某一天的所有數據

explain select * from t1 where date(c) ='2019-05-21';

 

查看圖中的執行計划,type 為 ALL,key 字段結果為 NULL,因此知道該 SQL 是沒走索引的全表掃描

原因:對條件字段做函數操作走不了索引

2.隱式轉換

概念:當操作符與不同類型的操作對象一起使用時,就會發生類型轉換以使操作兼容。某些轉換是隱式的

explain select * from t1 where a=1000;

未走索引原因:

a 字段類型是 varchar(20),而語句中 a 字段條件值沒加單引號,導致 MySQL 內部會先把a轉換成int型,再去做判斷,相當於實際執行的 SQL 語句如下:

select * from t1 where cast(a as signed int) =1000;

因此又回到上面說的:對索引字段做函數操作時,優化器會放棄使用索引

優化后:

explain select * from t1 where a='1000';

 

 

隱式轉換導致查詢慢的情況在工作中遇到過幾次,有時字段名對開發寫SQL產生了影響,比如曾經遇到過字段名是user_num,而實際字段類型是char,但是開發在寫SQL時誤認為是int型,導致漏寫單引號而發生隱式轉換。

所以建議在寫SQL時,先看字段類型,然后根據字段類型寫SQL 

3.模糊查詢(通配符在前面不走索引)

很多時候我們想根據某個字段的某幾個關鍵字查詢數據,比如會有如下 SQL:

 

 優化過的:

 

 缺點:結果會不准確

如果條件只知道中間的值,需要模糊查詢去查,那就建議使用ElasticSearch或其它搜索服務器

4.范圍查詢:

explain select * from t1 where b>=1 and b <=2000;

 

 

 結果:不走索引

發現並不能走b字段的索引。

原因:優化器會根據檢索比例、表大小、I/O塊大小等進行評估是否使用索引。比如單次查詢的數據量過大,優化器將不走索引。

優化范圍查詢(分批查詢)

explain select * from t1 where b>=1 and b <=1000;

 

 實際這種范圍查詢而導致使用不了索引的場景經常出現,比如按照時間段抽取全量數據,每條SQL抽取一個月的;或者某張業務表歷史數據的刪除。遇到此類操作時,應該在執行之前對SQL做explain分析,確定能走索引,再進行操作,否則不但可能導致操作緩慢,在做更新或者刪除時,甚至會導致表所有記錄鎖住,十分危險。

5.計算操作:

explain select * from t1 where b-1 =1000;

 

 原因:對索引字段做運算將使用不了索引。

計算操作的 SQL 優化

explain select * from t1 where b =1000 + 1;

 

 一般需要對條件字段做計算時,建議通過程序代碼實現,而不是通過MySQL實現。如果在MySQL中計算的情況避免不了,那必須把計算放在等號后面

總結以上結果:
  • 應該避免隱式轉換
  • like查詢不能以%開頭
  • 范圍查詢時,包含的數據比例不能太大
  • 不建議對條件字段做運算及函數操作




 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM