MySQL高級知識(六)——索引優化

前言:索引優化的目的主要是讓索引不失效,本篇經過相關案例對索引優化進行講解。html


0.準備

建立經典的tb_emp表。sql

DROP TABLE IF EXISTS `tb_emp`;
CREATE TABLE `tb_emp` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `age` int(11) NOT NULL,
  gender varchar(10) NOT NULL,
email varchar(20),
PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ---------------------------- INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Tom', '22','male','1@qq.com'); INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Mary', '21','female','2@qq.com'); INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Jack', '27','male','3@qq.com'); INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Rose', '23','female','4@qq.com');

注:建立了tb_emp表,並插入了4條數據。函數

1.最佳左前綴法則

#1.定義:在建立了多列索引的狀況下,查詢從索引的最左前列開始且不能跳過索引中的列優化

最佳左前綴法則就是說若是建立了多個索引,在使用索引時要按照建立索引的順序來使用,不能缺乏或跳過,固然若是隻使用最左邊的索引列,也就是第一個索引是能夠的,通俗理解:「帶頭大哥不能死,中間兄弟不能斷」。要點:「頭不能掉」。下面將用案例進行說明。spa

#2.建立組合索引,並執行explain。3d

Case 1:code

分析:htm

①索引的建立順序爲name,age,gender;blog

②直接使用name(帶頭大哥)做爲條件,能夠看到type=ref,key_len=82,ref=const,效果還不錯。索引

Case 2:

分析:

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

Case 3:

分析:

①對比上面兩句sql語句可發現:咱們使用:火車頭(name)和中間車箱(age)、火車頭(name)和車尾(gender)

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

③通俗理解:火車頭單獨跑沒問題,火車頭與直接相連的車箱一塊兒跑也沒問題,可是火車頭與車尾,若是中間沒有車箱,只能火車頭本身跑。

Case 4:

分析:

火車頭加車箱加車尾,三者串聯,就變成了奔跑的小火車。type=ref,key_len=128,ref=const,const,const。

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

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

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

Case 1:

分析:

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

Case 2:

分析:

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

結論:在索引列上作任何操做,都會致使索引失效轉向全表掃描

3.範圍右邊全失效

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

Case 1:

Case 2:

Case 3:

Case 4:

對以上4個case進行分析:

①條件單獨使用name時,type=ref,key_len=82,ref=const。

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

③當全值匹配時,type=ref,key_len=128,ref=const,const,const。說明索引所有用上,從key_len與ref能夠看出。

④當使用範圍時(age>27),type=range,key_len=86,ref=Null,與Case 一、Case2和Case3可知,使用了部分索引,但gender索引沒用上(與Case 3對比)。

結論:範圍右邊的索引列失效

4.儘可能使用覆蓋索引

儘可能使用覆蓋索引(查詢列和索引列儘可能一致,通俗說就是對A、B列建立了索引,而後查詢中也使用A、B列),減小select *的使用。

Case 1:

Case 2:

分析:

對比Case1和Case2,Case1使用select *,Case2使用覆蓋索引(查詢列與條件列對應),可看到Extra從Null變成了Using index,提升檢索效率。

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

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

6.is null 或 is not null也沒法使用索引

Case 1:

Case 2:

分析:

在使用is null的時候,索引徹底失效,使用is not null的時候,type=ALL全表掃描,key=Null索引失效。

這裏的例子可能有點特殊,具體狀況肯能和case上的有所不一樣,可是仍是要注意is null和is not null的使用。

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

Case 1:

Case 2:

Case 3:

分析:

like的%位置不一樣,所產生的效果不同,當%出如今左邊的時候type=ALL,key=Null(全表掃描,索引失效),當%出如今右邊的時候,type=range,索引未失效。

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

可是在實際生產環境中,%僅出如今右邊可能不可以解決咱們的問題,因此解決%出如今左邊索引失效的方法:使用覆蓋索引

Case 4:

分析:對比Case1可知,經過覆蓋索引type=index,而且使用了Using index,從全表掃描變成了全索引掃描,仍是不錯的。

Case 5:

分析:這裏出現type=index,由於主鍵自動建立惟一索引

Case 6:

分析:上面四組explain執行的結果都相同,代表都使用了索引,從這裏能夠深入的體會到覆蓋索引:徹底吻合或者沾邊(age),均可以使type=index。

Case 7:

分析:因爲只在(name,age,gender)上建立索引,當包含email時,致使結果集偏大(email未建索引)【鍋大,鍋蓋小,不能匹配】,因此type=ALL。

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

Case 1:

分析:上述兩條sql語句都能查詢出相同的數據。

Case 2:

分析:

經過explain執行結果能夠看出,字符串(name)不加單引號在查詢的時候,致使索引失效(type=ref變成了type=ALL,而且key=Null),並全表掃描。

結論:varchar類型的字段,在查詢的時候不加單引號致使索引失效,轉向全表掃描

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

結論:經過上述explain的執行結果可看出,在使用or鏈接的時候type=ALL,key=Null,索引失效,並全表掃描

總結

①全值匹配。

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

索引列上不計算

覆蓋索引記住用

不等於、is null、is not null致使索引失效

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

字符串不加單引號致使索引失效

少用or,用or致使索引失效


by Shawn Chen,2018.6.25日,上午。


相關內容

MySQL高級知識系列目錄

相關文章
相關標籤/搜索