MySQL高級知識(七)——索引優化準則

此博客的內容主要來源於尚硅谷的視頻中,在此記錄,以備以後自己查看。

準備

創建staff表:

DROP TABLE IF EXISTS `staffs`;
CREATE TABLE `staffs`(
  id INT PRIMARY KEY AUTO_INCREMENT,
  staname VARCHAR (24)  NULL DEFAULT '' COMMENT '姓名',
  age INT NOT NULL DEFAULT 0 COMMENT '年齡',
  email varchar(20) NULL DEFAULT '' COMMENT '郵箱',
  pos VARCHAR (20) NOT NULL DEFAULT '' COMMENT '職位',
  add_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入職時間'
) CHARSET utf8 COMMENT '員工記錄表' ;

INSERT INTO `staffs`(staname ,age,pos,add_time) VALUES('z3',22,'manager',NOW());
INSERT INTO `staffs`(staname ,age,pos,add_time) VALUES('July',23,'dev',NOW());
INSERT INTO `staffs`(staname ,age,pos,add_time) VALUES('2000',23,'dev',NOW());
INSERT INTO `staffs`(staname ,age,pos,add_time) VALUES(null,23,'dev',NOW());
SELECT * FROM staffs;

在這裏插入圖片描述

規則:

1. 最佳左前綴原則

1.1. 定義:

  • 在創建了多列索引的情況下,查詢從索引的最左前端列開始且不能跳過索引中的列
  • 最佳左前綴法則就是說,如果我們創建了多個索引,在使用索引的時候要按照創建索引的順序來使用,中間不能缺少或者跳過,當然如果知識使用了最左邊的索引列,也就是第一個索引是可以的。
  • 俗話理解就是"帶頭大哥不能死,中間兄弟不能斷"

1.2. 事例

  • 事例1

創建組合索引,並執行explain
在這裏插入圖片描述
分析:

  1. 索引的創建順序是staname,age,pos;
  2. 直接使用staname(帶頭大哥)作爲條件,可以看到type=ref,key_len=75,ref=const,效果不錯

  • 事例2

在這裏插入圖片描述
分析:

沒使用帶頭大哥(staname),直接使用兄弟,type=ALL,爲全表掃描。


  • 事例3

在這裏插入圖片描述
分析:
使用了帶頭大哥(staname),之後使用了age,所以type=ref,ref=const,const。

注意:
and 忽略左右關係。就是我們即使沒有按照順序,但是mysql由於優化器的存在,會自動優化這個。


  • 事例4

在這裏插入圖片描述
在這裏插入圖片描述
分析:

  1. 對比上面兩個sql語句可發現:火車頭(staname)和中間車廂(age)、火車頭(staname)和車尾(pos)。

  2. 雖然type=ref,但是觀察key_len和ref兩項,並對比Case1中的結果,可得出在使用火車頭(name)和車尾(gender)時,只使用了部分索引也就是火車頭(name)的索引。

  3. 通俗理解:火車頭單獨跑沒問題,火車頭與直接相連的車廂一起跑也沒問題,但是火車頭與車尾,如果中間沒有車廂,只能火車頭自己跑。


  • 事例5

在這裏插入圖片描述
分析:
火車頭 + 車廂 + 車尾,三者串聯,就變成了整個火車。type=ref,key_len=141,ref=const,const,const。此處的and左右順序關係可以忽略,mysql優化器會自動優化。

1.3. 總結

帶頭大哥不能死,中間兄弟不能斷;帶頭大哥可跑路,老二也可跟着跑,其餘兄弟只能死。

2. 不要在索引列上面做任何的操作

在索引列上面做任何的操作(計算、函數、(自動or手動)類型轉換),會導致索引失效從而轉向全表掃描。

  • 事例1

在這裏插入圖片描述
分析:

  • 這裏使用了函數計算,type=ALL,導致索引失效。

  • 事例2

在這裏插入圖片描述


分析:

  • 將name=‘Tom’的值修改爲‘123’,使用sql後,發生了類型轉換,type=ALL,導致全表掃描。

  • 如果條件爲where staname = ‘123’,那麼沒有發生類型轉換。


在索引列上做任何操作,都會導致索引失效轉向全表掃描。

3. 範圍右邊全失效

存儲引擎不能使用索引中範圍右邊的列,也就是說範圍右邊的索引列會失效。

  • 事例1

在這裏插入圖片描述


  • 事物2

在這裏插入圖片描述


  • 事物3

在這裏插入圖片描述


  • 事物4

在這裏插入圖片描述


  • 對比:
    • 條件單獨使用name時候,type=ref,key_len=75,ref=const。

    • 條件加上age時(使用常量等值),type=ref,key_len=79,ref=const,const。

    • 當全值匹配時,type=ref,key_len=141,ref=const,const,const。說明索引全部用上,從key_len和ref可以看出。(and忽略左右)

    • 當使用範圍時(age>22),type=79,key_len=79,ref=Null,與事例1、事例2和事例3可以,使用了部分索引,但是pos這個字段的索引並沒有使用上。


範圍右邊的索引列失效。

4. 儘量使用覆蓋索引

儘量使用覆蓋索引(查詢列和索引列儘量保持一直,通俗的講就是對A、B列創建了索引,然後查詢中儘量也使用A、B列),減少select * 的使用。

  • 事例1

在這裏插入圖片描述


  • 事例2

在這裏插入圖片描述


  • 分析:
    • 對比事例1和事例2,事例1使用了select * ,事例2使用了覆蓋索引(查詢列和條件列對應),可看到extra從Null變成了Using index,提高了檢索效率。

5. 使用不等於( !=或<>)會使索引失效

在這裏插入圖片描述

結論:使用!=會使type=ALL,key=Null,導致全表掃描,並且索引失效。

6. is not null也無法使用索引

在這裏插入圖片描述
結論:使用is not null的時候,type=ALL全表掃描,key=Null索引失效。

在這裏插入圖片描述
此處type=ref,key=idx_name_age_pos,表明可以使用索引的。
注意:is null是可以使用索引的。

7. like通配符以%開頭會使索引失效

  • 事例1

在這裏插入圖片描述


  • 事例2

在這裏插入圖片描述


  • 事例3

在這裏插入圖片描述


  • 分析:
  1. like的%位置不同,所產生的效果不一樣,當%出現在左邊的時候,type=ALL,key=Null(全表掃描,索引失效),當%出現在右邊的時候,type=range,索引未失效。

  2. like查詢爲範圍查詢,%出現在左邊,則索引失效。%出現在右邊索引未失效。口訣:like百分加右邊。

  3. 但是在實際生產環境中,%僅出現在右邊可能不能夠解決我們的問題,所以解決%出現在左邊索引失效的方法:使用覆蓋索引。


  • 事例4

在這裏插入圖片描述
分析:對比事例1可知,通過覆蓋所有type=index,並使用了Using index,從全表掃描變成了全所以掃描,還是不錯的。


  • 事例5

在這裏插入圖片描述

分析:這裏出現type=index,是因爲主鍵自動創建唯一索引


  • 事例6
explain select age from staffs where staname like '%Jack%';
explain select staname,age from staffs where staname like '%Jack%';
explain select staname,age,pos from staffs where staname like '%Jack%';
explain select id,staname,age,pos from staffs where staname like '%Jack%';
---
explain select pos from staffs where staname like '%Jack%';  #結果也一樣

在這裏插入圖片描述
分析:上面四組explain執行的結果都相同,表明都使用了索引,從這裏可以深刻的體會到覆蓋所有:完全吻合或者沾邊(age、pos),都可以使得type=index。


  • 事例7

在這裏插入圖片描述
分析:由於只在(staname、age、pos)上面創建索引,當包含email時候,導致結果集偏大(email未建立索引)【鍋大,鍋蓋小,不能匹配】,所以type=ALL。

8. 字符串不加單引號導致索引失效

在這裏插入圖片描述

分析:

  1. 上述兩條sql語句實際操作得到的數據是相同的。

  2. 通過explain執行結果可以看出,字符串(staname)不加單引號在查詢的時候,導致索引失效(type=ref準變成了type=ALL,並且key=Null),並且全表掃描。

varchar類型的字段,在查詢的時候不加單引號導致索引失效,轉向全表掃描。
因爲他可能會將這個轉變類型。

9. 少用or,用or連接會使索引失效

在這裏插入圖片描述

分析:通過上述explain的執行結果可以看出,在執行or連接的時候,type=ALL,key=Null,導致索引失效,並全表掃描。

總結:

  1. 全值匹配我最愛。

  2. 最佳左前綴法則: 帶頭大哥不能死,中間兄弟不能斷;帶頭大哥可跑路,老二也可跟着跑,其餘兄弟只能死。

  3. 索引列上不計算。

  4. 覆蓋索引記住用。

  5. 不等於、is not null導致索引失效。

  6. like百分加右邊,加左邊導致索引失效,解決方法:使用覆蓋索引。

  7. 字符串不加單引號導致索引失效。

  8. 少用or,用or導致索引失效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章