MySQL高級(四)、索引優化之索引失效問題

本文以案例形式介紹索引失效問題,並在最後給出索引失效的小結。

索引失效情況

  1. 全值匹配我最愛;
  2. 最佳左前綴法則:如果索引了多列,要遵守最左前綴法則,查詢從索引的最左前列開始,且不能跳過索引中的列
  3. 不在索引列上做任何操作(計算,函數,類型轉換),會導致索引失效而轉向全表掃描;
  4. 存儲引擎不能使用索引中範圍條件右邊的列,即範圍之後全失效
  5. 儘量使用覆蓋索引,只訪問索引的查詢(索引列和查詢列一致),減少selec *;
  6. MySQL在使用不等於(!= 或者<>)的時候無法使用索引會導致全表掃描;
  7. is not null 也無法使用索引,is null是可以使用索引的;
  8. like 以通配符開頭(’%aa’)索引會失效,變成全表掃描;
  9. 字符串不加單引號,索引失效;
  10. 少用 or,用它來連接時會索引失效

案例

創建員工表staffs,在staffs上創建索引idx_staffs_nameAgePos(name, age, pos),並在該表上分析上述索引失效的情況。

#建表和索引的語句
CREATE TABLE staffs (
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR (24)  NULL DEFAULT '' COMMENT '姓名',
  age INT NOT NULL DEFAULT 0 COMMENT '年齡',
  pos VARCHAR (20) NOT NULL DEFAULT '' COMMENT '職位',
  add_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入職時間'
) CHARSET utf8 COMMENT '員工記錄表' ;
 
INSERT INTO staffs(NAME,age,pos,add_time) VALUES('z3',22,'manager',NOW());
INSERT INTO staffs(NAME,age,pos,add_time) VALUES('July',23,'dev',NOW());
INSERT INTO staffs(NAME,age,pos,add_time) VALUES('2000',23,'dev',NOW());
INSERT INTO staffs(NAME,age,pos,add_time) VALUES(null,23,'dev',NOW());
SELECT * FROM staffs;
 
ALTER TABLE staffs ADD INDEX idx_staffs_nameAgePos(name, age, pos);
  1. 全值匹配表示索引列和查詢條件的字段全部匹配,精度高,key_len長度大,如
#索引字段爲name, age, pos,則查詢時最好全部匹配
EXPLAIN SELECT * FROM staffs WHERE NAME = 'z3'  AND age = 23 AND pos = 'manager';

在這裏插入圖片描述
2. 最佳左前綴法則

#沒有帶頭大哥,全表掃描,type爲all
EXPLAIN SELECT * FROM staffs WHERE pos = 'manager'; 
#缺少中間樓梯,key_len長度僅僅爲name的字節長度
EXPLAIN SELECT * FROM staffs WHERE NAME = 'z3' AND pos = 'manager';

在這裏插入圖片描述
3. 不在索引列上做任何操作,會導致索引失效而轉爲全表掃描

#使用索引
EXPLAIN SELECT * FROM staffs WHERE name = 'July';
#索引失效
EXPLAIN SELECT * FROM staffs WHERE left(NAME,4) = 'July';

在這裏插入圖片描述
4. 範圍之後全失效

#只使用到NAME 和age字段作爲索引,範圍之後的pos失效
EXPLAIN SELECT * FROM staffs WHERE NAME = 'z3'  AND age < 11 AND pos = 'manager';

在這裏插入圖片描述
5. 儘量使用覆蓋索引

#未使用覆蓋索引
EXPLAIN SELECT * FROM staffs WHERE NAME = 'z3'  AND age = 23 AND pos = 'manager';
#使用覆蓋索引
EXPLAIN SELECT name, age, pos FROM staffs WHERE NAME = 'z3'  AND age = 23 AND pos = 'manager';

在這裏插入圖片描述
6. 使用 != 或者 <>導致索引失效

#使用索引
EXPLAIN SELECT * FROM staffs WHERE NAME = 'z3';
#索引失效,全表掃描,要全表遍歷一遍
EXPLAIN SELECT * FROM staffs WHERE NAME != 'z3';

在這裏插入圖片描述
7.IS NOT NULL無法使用索引,IS NULL可以使用索引

#IS NOT NULL無法使用索引
EXPLAIN SELECT * FROM staffs WHERE NAME IS NOT NULL;
#IS NULL可以使用索引
EXPLAIN SELECT * FROM staffs WHERE NAME IS NULL;
#選擇條件就是索引字段可以使用索引
EXPLAIN SELECT name FROM staffs WHERE NAME IS NOT NULL;

在這裏插入圖片描述
在這裏插入圖片描述
8. Like以通配符開頭,索引失效

#like以通配符開頭,索引失效
EXPLAIN SELECT * FROM staffs WHERE NAME LIKE '%uly';
#通配符放後面可以使用索引
EXPLAIN SELECT * FROM staffs WHERE NAME LIKE 'Jul%';

在這裏插入圖片描述
9. 字符串不加單引號,索引失效
我們在staffs表中有一個name爲2000的員工,通過姓名查找,若不加單引號能夠找到該行,但是變爲全表掃描
在這裏插入圖片描述
10. 使用OR,導致索引失效

select * from staffs where name = 'July' or name = 'z3';
#使用or導致索引失效
explain select * from staffs where name = 'July' or name = 'z3';

在這裏插入圖片描述

索引小結

Where語句 索引是否被使用
where a = 3 Y,使用到a
where a = 3 and b = 5 Y,使用到a, b
where a = 3 and b = 5 and c = 4 Y,使用到a, b, c
where b = 3 或者 where b = 3 and c = 4 或者 where c = 4 N
where a = 3 and c = 5 使用到a,但是c不可以,b中間斷了
where a = 3 and b > 4 and c = 5 使用到a和b,c不能用在範圍之後,b斷了
where a = 3 and b like ‘kk%’ and c = 4 Y,使用到a,b,c
where a = 3 and b like ‘%kk’ and c = 4 Y,使用到a
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章