什麼是MySQL的執行計劃(Explain關鍵字)?

2021-03-02 Hollis

本文作者王良辰,京東中臺架構師,擅長分布式系統及高可用、高並發系統架構與設計。曾經為企業開發過多個通用腳手架,推崇以技術手段提升開發效率、約束開發行為。


什麼是Explain


Explain被稱為執行計劃,在語句之前增加 explain 關鍵字,MySQL 會在查詢上設置一個標記,模擬MySQL優化器來執行SQL語句,執行查詢時,會返回執行計劃的信息,並不執行這條SQL。(注意,如果 from 中包含子查詢,仍會執行該子查詢,將結果放入臨時表中)。

Explain可以用來分析SQL語句和表結構的性能瓶頸。通過explain的結果,可以了解到如數據表的查詢順序、數據查詢操作的操作類型、哪些索引可以被命中、哪些索引實際會命中、每個數據表有多少行記錄被查詢等信息。


Explain命令擴展
explain extended

在explain的基礎上提供一些額外的查詢信息,在explian extended執行以後,通過show warnings命令可以得到優化後的查詢語句,可以看出優化器做了哪些工作,還可以通過某些數據估算表連接的行數。


explain partitions

用於分析使用了分區的表,會顯示出可能用到的分區。


兩點重要提示
1. Explain結果是基於數據表中現有數據的。
2. Explain結果與MySQL版本有很大的關係,不同版本的優化器的優化策略不同。

 

本文示例使用的資料庫表


Explain命令(關鍵字)


explain簡單示例

mysql>explain select * from t_user;

在查詢中的每個」表」會輸出一行,這裡的「表」的意義非常廣泛,不僅僅是資料庫表,還可以是子查詢、一個union 結果等。


explain結果列說明
【id列】

id列是一個有順序的編號,是查詢的順序號,有幾個 select 就顯示幾行。id的順序是按 select 出現的順序增長的。id列的值越大執行優先級越高越先執行,id列的值相同則從上往下執行,id列的值為NULL最後執行。


【select_type列】

select_type列的值標明查詢的類型:

1)simple:表明當前行對應的select是簡單查詢,不包含子查詢和union

2)primary:表明當前行對應的select是複雜查詢中最外層的 select

3)subquery:表明當前行對應的select是包含在 select 中的子查詢(不在 from 子句中)

4)derived:表明當前行對應的select是包含在 from 子句中的子查詢。

MySQL會創建一個臨時表來存放子查詢的查詢結果。用如下的語句示例說明:

explain select (select 1 fromt_user where user_id=1) from (select * from t_group where group_id=1) tmp;

*注意,在資料收集過程中,發現不同版本的MySQL表現不一致,經反覆對比,5.7及以後版本的輸出如下:

很顯然,MySQL在這方面進行了優化.

*注意,MySQL不同版本Explain表現差異很大,有些場景,從語句層面看,是要使用到索引,但經過優化器分析,結合表中現有數據,如果MySQL認為全表掃描性能更優,則會使用全表掃描。

5)union:表明當前行對應的select是在 union 中的第二個和隨後的 select

6)union result:表明當前行對應的select是從 union 臨時表檢索結果的 select

explain select 1 union all select 2 fromdual;

       MySQL5.7及以後同樣做了優化

【table列】

table列的結果表明當前行對應的select正在訪問哪個表。當查詢的<from>子句中有子查詢時,table列是 <derivedN> 格式,表示當前的select依賴 id=N結果行對應的查詢,要先執行 id序號=N 的查詢。當存在 union 時,UNION RESULT 的 table 列的值為<unionN1,N2>,N1和N2表示參與 union 的select 行的id序號。


【type列】

type列的結果表明當前行對應的select的關聯類型或訪問類型,也就是優化器決定怎麼查找數據表中的行,以及查找數據行記錄的大概範圍。該列的取值優化程度的優劣,從最優到最差依次為:null>system> const > eq_ref > ref > range > index > ALL。一般來說,要保證查詢達到range級別,最好達到ref。

1)null,MySQL優化器在優化階段分解查詢語句,在優化過程中就已經可以得到結果,那麼在執行階段就不用再訪問表或索引。

explain select min(user_id) from t_user;

這時的函數min,在索引列user_id中選取最小值,可以直接查找索引來完成,不需要執行時再訪問數據表。

2)const和system:const出現在用 primary key(主鍵) 或 unique key(唯一鍵) 的所有列與常數比較時,優化器對查詢進行優化並將其部分查詢轉化成一個常量。最多有一個匹配行,讀取1次,速度非常快。而system是const的特例,表中數據只有一條匹配時為system。此時可以用explain extended+show warnings查看執行結果。

explain extended select * from (select * from t_user where user_id = 1) tmp;

show warnings;

MySQL5.7及以後版本優化後:

3)eq_ref:primary key(主鍵)或 unique key(唯一鍵) 索引的所有構成部分被join使用 ,只會返回一條符合條件的數據行。這是僅次於const的連接類型。

explain select * from t_group_user gu left join t_group g ong.group_id = gu.group_id;

4) ref:與eq_ref相比,ref類型不是使用primary key(主鍵) 或 unique key(唯一鍵)等唯一索引,而是使用普通索引或者聯合唯一性索引的部分前綴,索引和某個值相比較,可能會找到符合條件的多個數據行。

1. 如下示例,使用的group_name是普通索引

explain select * from t_group where group_name= 'group1';

2.關聯表查詢

explain select g.group_id from t_group gleft join t_group_user gu on gu.group_id = g.group_id;

5)range:出現在 in(),between ,> ,<, >= 等操作符中。使用一個索引來查詢給定範圍的行。

6)index:掃描全表索引(index是從索引中讀取的,所有欄位都有索引,而all是從硬碟中讀取),比ALL要快。

explain select * from t_group;

7)all:即全表掃描,需要從頭到尾去查找所需要的行。一般這種情況下這需要增加索引來進行查詢優化了

explain select * from t_user;


【possible_keys列】

這一列的結果表明查詢可能使用到哪些索引。但有些時候也會出現出現possible_keys 列有結果,而 後面的key列顯示 null 的情況,這是因為此時表中數據不多,優化器認為查詢索引對查詢幫助不大,所以沒有走索引查詢而是進行了全表掃描。 

如果possible_keys列的結果是null,則表明沒有相關的索引。這時,可以通過優化where子句,增加恰當的索引來提升查詢性能。


【key列】

這一列表明優化器實際採用哪個索引來優化對該表的訪問。如果沒有使用索引,則該列是 null。


【key_len列】

這一列表明了在索引裡使用的字節數,通過這個值可以大致估算出具體使用了聯合索引中的前幾個列。 

key_len計算規則這裡不再贅述,不同的數據類型所佔的字節數是不一致的。


【ref列】

這一列表明了在key列記錄的索引中,表查找值所用到的列或常量,常見的有:const(常量),欄位名,如user.user_id


【rows列】

這一列表明優化器大概要讀取並檢測的行數。跟實際的數據行數大部分情況是不一致的。


【Extra列】

顧名思義,這一列表明的是額外信息,這一列的取值對優化SQL非常有參考意義。常見的重要取值如下: 

1)using index:所有被查詢的欄位都是索引列(稱為覆蓋索引),並且where條件是索引的前導列,出現這樣的結果,是性能高的表現。

explainselect group_id,group_name from t_group;

2)using where:被查詢的列未被索引覆蓋,where條件也並非索引的前導列,表示 MySQL 執行器從存儲引擎接收到查詢數據,再進行「後過濾」(Post-filter)。所謂「後過濾」,就是先讀取整行數據,再檢查此行是否符合 where 句的條件,符合就留下,不符合便丟棄。

explain select * from t_user whereuser_name='user1';

3)using where Using index:被查詢的列被索引覆蓋,並且where條件是索引列之一但是不是索引的前導列,也就是沒有辦法直接通過索引來查詢到符合條件的數據

explain select * from t_group where group_name = 'group1';

4)null:被查詢的列沒有被索引覆蓋,但where條件是索引的前導列,此時用到了索引,但是部分列未被索引覆蓋,必須通過「回表查詢」來實現,不是純粹地用到了索引,也不是完全沒用到索引

explain select * from t_user where user_id='1';

5)using index condition:與using where類似,查詢的列不完全被索引覆蓋,where條件中是一個前導列的範圍;這種情況未能通過示例顯現,可能跟MySQL版本有關係。

6) using temporary:這表明需要通過創建臨時表來處理查詢。出現這種情況一般是要進行優化的,用索引來優化。創建臨時表的情況:distinct,group by,orderby,子查詢等

explain select distinct user_name from t_user;

explain select distinct group_name fromt_group; --group_name是索引列

7) usingfilesort:在使用order by的情況下出現,mysql會對結果使用一個外部索引排序,而不是按索引次序從表裡讀取行。此時mysql會根據聯接類型瀏覽所有符合條件的記錄,並保存排序關鍵字和行指針,然後排序關鍵字並按順序檢索行信息。這種情況下要考慮使用索引來優化的。

explain select * from t_user orderby user_name;

explain select * from t_group order bygroup_name;  --group_name是索引列

查詢優化建議


結合前面的描述,首先看 type列的結果,如果有類型是 all 時,表示預計會進行全表掃描(fulltable scan)。通常全表掃描的代價是比較大的,建議創建適當的索引,通過索引檢索避免全表掃描。

再來看下 Extra 列的結果,如果有出現 Using temporary 或者 Using filesort 則要多加關注:

Using temporary,表示需要創建臨時表以滿足需求,通常是因為GROUP BY的列沒有索引,或者GROUP BY和ORDER BY的列不一樣,也需要創建臨時表,建議添加適當的索引。

Using filesort,表示無法利用索引完成排序,也有可能是因為多表連接時,排序欄位不是驅動表中的欄位,因此也沒辦法利用索引完成排序,建議添加適當的索引。

Using where,通常是因為全表掃描或全索引掃描時(type 列顯示為 ALL 或index),又加上了WHERE條件,建議添加適當的索引。



索引使用情況分析
資料庫表


主鍵索引:demo_id

聯合索引:c1,c2,c3

實例說明
實例一:

explain select * from t_demo where c1='d1'and c2='d2' and c3='d3';

explain select * from t_demo where c2='d2'and c1='d1' and c3='d3';

explain select * from t_demo where c3='d3'and c1='d1' and c2='d3';

幾個Sql表現一致

type=ref,ref=const,const,const

執行常量等值查詢時,改變索引列的順序並不會更改explain的執行結果,優化器會進行優化,推薦按照索引順序列編寫sql語句。

實列二:

explain select * from t_demo where c1='d1'and c2>'d2' and c3='d3';

explain select * from t_demo where c1='d1'and c3>'d3' and c2='d2';

第一個例子範圍右側索引失效,使用到了兩個索引。

第二個例子,由於優化器優化的原因,使用到了全部的三個索引。


實例三:

explain select * from t_demo wherec1>'c' and c2='d2' and c3='d3';

explain select * from t_demo wherec1>'e' and c2='d2' and c3='d3';

從上面兩個實例可以發現,同樣使用最左的索引列範圍查詢,有些情況未用到索引,做了全表掃描(第一個例子);有些情況使用到了索引(第二個例子)。

經反覆驗證,發現如下規律(不一定可靠),也可能與數據的第一行或最小值相關。

1. 跟存儲的數據有關

2. 在大於條件下,如果條件數據小於列數據,則索引無效;如果條件數據大於列數據,則索引有效;

在設計查詢條件時,請注意規避。

針對第一個例子,可以採用覆蓋索引的方式優化。


實例四:

explain select * from t_demo where c1='d1'and c2='d2' order by c3;

explain select * from t_demo where c1='d1'order by c3;

explain select * from t_demo where c1='d1'and c3='d3' order by c2;

order by排序使用到索引和沒使用到索引的情況


實例五:

explain select * from t_demo where c1='d1'and c4='d4' order by c1,c2;

條件列包含沒有索引的列,出現了Using filesort


實例六:

explain select * from t_demo where c1='d1'and c4='d4' group by c1,c2;

性能非常差的場景,同時出現了Using temporary和Using filesort



總結

1. 兩種方式的排序filesort和index,Usingindex是指MySQL掃描索引本身完成排序。index效率高,filesort效率低。

2. order by滿足兩種情況會使用Using index。

1)order by語句使用索引最左前列。

2)使用where子句與order by子句條件列組合滿足索引最左前列。

3. 儘量在索引列上完成排序,遵循索引建立(索引創建的順序)時的最佳左前綴法則。

4. group by與order by很類似,都是先排序後分組,遵照索引創建順序的最佳左前綴法則。


有道無術,術可成;有術無道,止於術

歡迎大家關注Java之道公眾號


好文章,我在看❤️

相關焦點

  • MySQL之Explain詳解
    ,這個執行計劃展示了接下來具體執行查詢的方式,比如多表連接的順序是什麼,對於每個表採用什麼訪問方法來具體執行查詢等等。如果我們想看看某個查詢的執行計劃的話,可以在具體的查詢語句前邊加一個EXPLAIN,就像這樣:mysql> EXPLAIN SELECT 1;+----+---+--+--+-++-+----+-+-++-+| id | select_type | table | partitions | type | possible_keys
  • MySQL優化:定位慢查詢的兩種方法以及使用explain分析SQL
    一條SQL查詢語句在經過MySQL查詢優化器處理後會生成一個所謂的執行計劃,這個執行計劃展示了具體執行查詢的方式,比如多表連接的順序是什麼,對於每個表採用什麼訪問方法來具體執行查詢等等。本章的內容就是為了幫助大家看懂EXPLAIN語句的各個輸出項都是幹嘛使的,從而可以有針對性的提升我們查詢語句的性能。
  • mysql的explain詳解
    然後我馬上看了下idx_1是什麼索引 ,idx_1(book_id)這個沒有使用到。然後我改了一下sql,重新explain一下結果,如下:explain SELECT * FROM article force index(idx_1) WHERE (id < 4054495) AND (book_id = '5164') ORDER BY id desc LIMIT 1\G;
  • mysql性能分析explain之id詳解
    前言在mysql的編程世界裡,有時候我們往往需要對自己編寫的sql語句進行分析,來去查看sql的執行計劃,這個還是很有必要的。因為我們在開發中,往往需要從資料庫中查詢數據,當數據量一旦大的時候,這個時候就會出現查詢瓶頸,我們首先呢可能就會去查看我們的sql語句的執行過程,判斷是否可進行優化,那如何去定位分析呢?這個就是本文講到的使用explain工具來去定位分析。
  • MySQL高級知識(四)——Explain
    explain(執行計劃),使用explain關鍵字可以模擬優化器執行sql查詢語句,從而知道MySQL是如何處理sql語句。explain主要用於分析查詢語句或表結構的性能瓶頸。註:本系列隨筆如無特殊說明都MySQL版本都為5.7.22。
  • 技術分享 | MySQL 執行 GROUP BY 的四種方式
    這樣,我們可以逐組掃描數據並動態執行 GROUP BY(低成本)。當我們使用 LIMIT 限制我們檢索的組的數量或使用「覆蓋索引」時,特別有效,因為順序索引掃描是一種非常快速的操作。如果您有少量組,並且沒有覆蓋索引,索引順序掃描可能會導致大量 IO。所以這可能不是最優化的計劃。
  • MySQL中SQL執行計劃,你理解了嗎?
    首先我們來看一下什麼是執行計劃:執行計劃就是解釋select語句如何在資料庫執行的、相關表是怎麼連接、連接的次序、有哪些索引和索引使用情況、每個表的掃描數據量等等。簡單來說,就是通過數據來分析select語句的執行情況;怎麼查看執行計劃:查看執行需要用到關鍵字EXPLAIN,將EXPLAIN放在SQL語句的前面( EXPLAIN [EXTENDED] SELECT select_options ),如下圖:從上圖可以看出,通過執行計劃展示了表格數據,這個表格有id、select_type
  • MySQL EXPLAIN 命令詳解
    MySQL的EXPLAIN命令用於SQL語句的查詢執行計劃(QEP)。這條命令的輸出結果能夠讓我們了解MySQL 優化器是如何執行SQL 語句的。這條命令並沒有提供任何調整建議,但它能夠提供重要的信息幫助你做出調優決策。一、語法MySQL 的EXPLAIN 語法可以運行在SELECT 語句或者特定表上。
  • 在mysql中如何刪除記錄?delete關鍵字了解一下
    在上一篇文章中我們學習了如何更新mysql中的數據內容,用到的是update這個關鍵字,今天我們要學習的是如何讓在mysql中刪除記錄,也就是從箱子裡面拿走東西,用到的關鍵字是delete這個關鍵字,下面我們就通過一個例子來了解一下。
  • MySQL EXPLAIN 命令詳解學習
    (點擊上方公眾號,可快速關注)作者:黃杉blog.csdn.net/mchdba/article/details/9190771如有好文章投稿,請點擊 → 這裡了解詳情MySQL EXPLAIN 命令詳解MySQL的EXPLAIN命令用於SQL語句的查詢執行計劃
  • Mysql中in到底走不走索引?
    當前找工作,對於一定年限的軟體開發者,都會被問到索引的相關問題,最近我發現對於mysql資料庫中in關鍵字走不走索引,有很多面試者回答的都不貼切
  • mysql中explain輸出列之id的用法詳解
    參考mysql5.7 en manual,對列id的解釋:The SELECT identifier. This is the sequential number of the SELECT within the query.
  • 全網最全 | MySQL EXPLAIN 完全解讀
    TIPS本文基於MySQL 8.0編寫,理論支持MySQL 5.0及更高版本。explain可用來分析SQL的執行計劃。也就是說,對於t1中的每一行,MySQL只需要在t2中只執行一次查找,而不考慮在t2中實際匹配的行數。在MySQL 8.0.17及更高版本中,如果出現此提示,還可表示形如 NOT IN (subquery) 或 NOT EXISTS (subquery) 的WHERE條件已經在內部轉換為反連接。這將刪除子查詢並將其表放入最頂層的查詢計劃中,從而改進查詢的開銷。
  • 「MySQL系列」分析Sql執行時間及查詢執行計劃(附資料庫和一千萬數據)
    show profiles是mysql提供可以用來分析當前會話中語句執行的資源消耗情 況。可以用來SQL的調優測量。2.1.1 設置MySQL支持profile1.重啟mysql服務service mysqld restart備註 如果執行命令報如下錯誤
  • MySQL Explain詳解
    命令:可查看SQL語句的執行計劃,查看SQL語句有沒有使用上了索引,有沒有做全表掃描,這都可以通過explain命令來查看。利用explain命令查看SQL語句的執行計劃: • EXPLAIN不能顯示MySQL在執行查詢時所作的優化工作。• 部分統計信息是估算的,並非精確值。• EXPALIN只能解釋SELECT操作,其他操作要重寫為SELECT後查看執行計劃。
  • MySQL的explain詳解
    explain 執行計劃分析目前可以對select update insert replace delete 進行分析可以從explain知道sql如何使用索引聯接查詢的執行順序查詢掃描的數據行數例如:id:1select_type:simpletable: product_commentpartitions
  • SQL中EXPLAIN命令詳解
    >rows預計需要掃描的記錄數,預計需要掃描的記錄數越小越好Extra額外附加信息,主要確認是否出現 Using filesort、Using temporary 這兩種情況explain 展示mysql執行計劃使用方法,在select語句前加上explain就可以了,
  • MySQL-SQL語句執行流程
    查看連接狀態:SHOW FULL PROCESSLIST命令來查看MySQL正在做什麼,如:locked:該線程正在等待表鎖(實現鎖是在存儲引擎中)analyzing and statistics:線程正在收集存儲引擎的統計信息,並生產相應的查詢計劃copying to tmp table:線程正在查詢,並將結果放到一個臨時表中,這時候一般是在做group bu操作sending data:
  • MySQL EXPLAIN 詳解
    (點擊上方公眾號,可快速關注)來源:高廣超www.jianshu.com/p/ea3fc71fdc45如有好文章投稿,請點擊 → 這裡了解詳情MySQL EXPLAIN命令是查詢性能優化不可缺少的一部分,本文主要講解explain
  • MySQL何時執行flush privileges?
    需求背景我們平時在給用戶授權grant語句執行後,都習慣性的執行一個命令flush privileges;,但是我發現有時候不執行這個命令,授權語句執行之後,權限驗證也是OK的,但是有時候發現不執行這個flush privileges;命令,權限認證還不能通過。