詳解Mysql執行計劃explain

1、MySQL語法

MySql提供了EXPLAIN語法用來進行查詢分析,在SQL語句前加一個”EXPLAIN”即可。

默認情況下Mysql的profiling是關閉的,所以首先必須打開profiling

set profiling=“ON”

mysql> show variables like "%profi%";  
 ------------------------ -------   
| Variable_name          | Value |  
 ------------------------ -------   
| profiling              | ON    |  

默認情況下Mysql的profiling是關閉的,所以首先必須打開profiling
mysql> set profiling="ON"  
 


show processlist;   查看現在在運行的所有進程列表,在進程列表中我們唯一需要的是ID  
mysql> show processlist;  
 ---- ------ ---------------- ----------- --------- ------ ------- -------------  
-----   
| Id | User | Host           | db        | Command | Time | State | Info  
     |  
 ---- ------ ---------------- ----------- --------- ------ ------- -------------  
-----   
|  3 | root | localhost:2196 | click_log | Query   |    0 | NULL  | show process  
list |  
 ---- ------ ---------------- ----------- --------- ------ ------- -------------  
mysql> show profile cpu,memory for query 3;  
 -------------------- ------------ ---------- ------------   
| Status             | Duration   | CPU_user | CPU_system |  
 -------------------- ------------ ---------- ------------   
| freeing items      | 0.00001375 |     NULL |       NULL |  
| logging slow query | 0.00001375 |     NULL |       NULL |  
| cleaning up        | 0.00000050 |     NULL |       NULL |  

2、Navicat工具

打開profile分析工具:
查看是否生效:show variable like ‘%profil%’;
查看進程:show processlist;
選擇數據庫:use db_jiakao;
全部分析的類型:show PROFILE all;
查看錶索引:show index from user_member;##查看錶索引
使用explain命令查看query語句的性能

解釋

輸出列 含義
id 查詢標識
select_type 查詢類型
table 查詢涉及的表
partitions 匹配到的分區信息
type 連接類型
possible_keys 可能選擇的索引
key 實際使用的索引
key_len 實際使用的索引的長度
ref 和索引進行比較的列
rows 需要被檢索的大致行數
filtered 按表條件過濾的行百分比
Extra 額外信息

1、ID、table

id:Query Optimizer 所選定的執行計劃中查詢的序列號

  1. id相同時,執行順序由上至下
  2. 如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
    3.id如果相同,可以認爲是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行

table:顯示這一行的數據是關於哪張表的

2、type

顯示連接使用了何種類型,對錶所使用的訪問方式。從最好到最差的連接類型爲const、eq_reg、ref、range、indexhe和ALL

說明:不同連接類型的解釋(按照效率高低的順序排序)
system:系統表,表中只有一行數據。這是const連接類型的特殊情況。

const :讀常量,且最多隻會有一條記錄匹配。表中的一個記錄的最大值能夠匹配這個查詢(索引可以是主鍵或惟一索引)。因爲只有一行,這個值實際就是常數,因爲MYSQL先讀這個值然後把它當做常數來對待。

eq_ref:最多隻會有一條匹配結果,一般是通過主鍵或者唯一鍵索引來訪問;在連接中,MYSQL在查詢時,從前面的表中,對每一個記錄的聯合都從表中讀取一個記錄,它在查詢使用了索引爲主鍵或惟一鍵的全部時使用。

ref:Join 語句中被驅動表索引引用查詢,這個連接類型只有在查詢使用了不是惟一或主鍵的鍵或者是這些類型的部分(比如,利用最左邊前綴)時發生。對於之前的表的每一個行聯合,全部記錄都將從表中讀出。這個類型嚴重依賴於根據索引匹配的記錄多少—越少越好。

range:索引範圍掃描,這個連接類型使用索引返回一個範圍中的行,比如使用>或<查找東西時發生的情況。

ref_or_null:與ref 的唯一區別就是在使用索引引用查詢之外再增加一個空值的查詢。

unique_subquery:子查詢中的返回結果字段組合是主鍵或者唯一約束

index_merge:查詢中同時使用兩個(或更多)索引,然後對索引結果進行merge 之後再讀取表數據;

index_subquery:子查詢中的返回結果字段組合是一個索引(或索引組合),但不是一個主鍵或者唯一索引;

index:全索引掃描,這個連接類型對前面的表中的每一個記錄聯合進行完全掃描(比ALL更好,因爲索引一般小於表數據)。

ALL:全表掃描,這個連接類型對於前面的每一個記錄聯合進行完全掃描,這一般比較糟糕,應該儘量避免。

3、possible_keys 、key_len

possible_keys
顯示可能應用在這張表中的索引。這裏的索引名字是創建索引時指定的索引暱稱;如果索引沒有暱稱,則默認顯示的是索引中第一個列的名字。
如果爲空,沒有可能的索引,可以爲相關的域從WHERE語句中選擇一個合適的語句

key_len
表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度(key_len顯示的值爲索引字段的最大可能長度,並非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的)
不損失精確性的情況下,長度越短越好

4、key

實際使用的索引。如果爲NULL,則沒有使用索引。很少的情況下,MYSQL會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MYSQL忽略索引
key_len
使用的索引的長度。在不損失精確性的情況下,長度越短越好

5、ref

顯示的是列的名字,顯示索引的哪一列被使用了,MySQL將根據這些列來選擇行,如果可能的話,是一個常數 。
“對於每一種與另一個表中記錄的組合,MySQL將從當前的表讀取所有帶有匹配索引值的記錄。如果連接操作只使用鍵的最左前綴,或者如果鍵不是 UNIQUE或PRIMARY KEY類型(換句話說,如果連接操作不能根據鍵值選擇出唯一行),則MySQL使用ref連接類型。如果連接操作所用的鍵只匹配少量的記錄,則ref是一 種好的連接類型。”

6、rows

MYSQL認爲必須檢查的用來返回請求數據的行數 ,這裏最理想的數字就是1。

7、select_type

查詢類型 含義
SIMPLE 簡單查詢(不包含子查詢或UNION)
PRIMARY 最外層查詢
UNION UNION語句中第二或更後面的查詢
DEPENDENT UNION 依賴外部查詢的UNION中第二或更後面的查詢
UNION RESULT UNION語句的結果集
SUBQUERY 子查詢中的第一個查詢
DEPENDENT SUBQUERY 依賴外部查詢的子查詢中的第一個查詢
DERIVED 查詢的派生表(在FROM從句中的子查詢)
MATERIALIZED 物化子查詢
UNCACHEABLE SUBQUERY 無法緩存結果的子查詢,並且必須爲外部查詢的每一行重新計算
UNCACHEABLE UNION 屬於無法緩存的子查詢的UNION的第二或更後面的查詢

所使用的查詢類型,判斷是否是複雜語句,主要有以下這幾種查詢類型

DEPENDENT SUBQUERY:子查詢中內層的第一個SELECT,依賴於外部查詢的結果集;
DEPENDENT UNION:子查詢中的UNION,且爲UNION 中從第二個SELECT 開始的後面所有SELECT,同樣依賴於外部查詢的結果集;
PRIMARY:子查詢中的最外層查詢,注意並不是主鍵查詢;
SIMPLE:除子查詢或者UNION 之外的其他查詢;
SUBQUERY:子查詢內層查詢的第一個SELECT,結果不依賴於外部查詢結果集;
UNCACHEABLE SUBQUERY:結果集無法緩存的子查詢;
UNION:UNION 語句中第二個SELECT 開始的後面所有SELECT,第一個SELECT 爲PRIMARY
UNION RESULT:UNION 中的合併結果;
DERIVED:派生表的SELECT, FROM子句的子查詢

8、Extra

關於MYSQL如何解析查詢的額外信息。將在表4.3中討論,但這裏可以看到的壞的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,結果是檢索會很慢

說明:extra列返回的描述的意義

Distinct :一旦mysql找到了與行相聯合匹配的行,就不再搜索了。

Not exists :mysql優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標準的行,就不再搜索了。

No tables:Query 語句中使用FROM DUAL 或者不包含任何FROM 子句;

Using filesort:當我們的Query 中包含ORDER BY 操作,而且無法利用索引完成排序操
作的時候,MySQL Query Optimizer 不得不選擇相應的排序算法來實現。看到這個的時候,查詢就需要優化了。mysql需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行。

Using index:所需要的數據只需要在Index 即可全部獲得而不需要再到表中取數據。列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對錶的全部的請求列都是同一個索引的部分的時候。

Using temporary :當MySQL 在某些操作中必須使用臨時表的時候,在Extra 信息中就會
出現Using temporary 。主要常見於GROUP BY 和ORDER BY 等操作中。看到這個的時候,查詢需要優化了。這裏,mysql需要創建一個臨時表來存儲結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上。

Using where:如果我們不是讀取表的所有數據,或者不是僅僅通過索引就可以獲取所有需
要的數據,則會出現Using where 信息;

Where used:使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,並且連接類型ALL或index,這就會發生,或者是查詢有問題。

Using index for group-by:數據訪問和Using index 一樣,所需數據只需要讀取索引即
可,而當Query 中使用了GROUP BY 或者DISTINCT 子句的時候,如果分組字段也在索引
中,Extra 中的信息就會是Using index for group-by;

Using where with pushed condition:這是一個僅僅在NDBCluster 存儲引擎中才會出現
的信息,而且還需要通過打開Condition Pushdown 優化功能纔可能會被使用。控制參數
爲engine_condition_pushdown 。

Full scan on NULL key:子查詢中的一種優化方式,主要在遇到無法通過索引訪問null
值的使用使用;

Impossible WHERE noticed after reading const tables:MySQL Query Optimizer 通過
收集到的統計信息判斷出不可能存在結果;

Select tables optimized away:當我們使用某些聚合函數來訪問存在索引的某個字段的
時候,MySQL Query Optimizer 會通過索引而直接一次定位到所需的數據行完成整個查
詢。當然,前提是在Query 中不能有GROUP BY 操作。如使用MIN()或者MAX()的時
候;

Range checked for each Record(index map:#) :沒有找到理想的索引,因此對從前面表中來的每一個行組合,mysql檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連接之一。

總結

• EXPLAIN不會告訴你關於觸發器、存儲過程的信息或用戶自定義函數對查詢的影響情況
• EXPLAIN不考慮各種Cache
• EXPLAIN不能顯示MySQL在執行查詢時所作的優化工作
• 部分統計信息是估算的,並非精確值
• EXPALIN只能解釋SELECT操作,其他操作要重寫爲SELECT後查看執行計劃。

因此,弄明白了explain語法返回的每一項結果,我們就能知道查詢大致的運行時間了,如果查詢裏沒有用到索引、或者需要掃描的行過多,那麼可以感到明顯的延遲。因此需要改變查詢方式或者新建索引。mysql中的explain語法可以幫助我們改寫查詢,優化表的結構和索引的設置,從而最大地提高查詢效率。當然,在大規模數據量時,索引的建立和維護的代價也是很高的,往往需要較長的時間和較大的空間,如果在不同的列組合上建立索引,空間的開銷會更大。因此索引最好設置在需要經常查詢的字段中

拓展

EXPLAIN FORMAT=json和EXPLAIN ANALYZE查詢計劃解讀:https://blog.csdn.net/weixin_38004638/article/details/106427205

參考:
https://blog.csdn.net/y41992910/article/details/79888276
https://www.cnblogs.com/xu-xiang/p/5833349.html
https://www.cnblogs.com/xuanzhi201111/p/4175635.html

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