首頁 > 軟體

MySQL EXPLAIN執行計劃解析

2022-08-22 14:03:13

前言

呼叫EXPLAIN可以獲取關於查詢執行計劃的資訊,以及如何解釋輸出。EXPLAIN命令是檢視查詢優化器如何決定執行查詢的主要方法,但該動能也有侷限性,它的選擇並不總是最優的,展示的也並不一定是真相。

1 呼叫EXPLAIN

要使用EXPLAIN,只需要在SELECT 關鍵字之前增加 EXPLAIN這個詞。MySQL會在查詢上設定一個標記。當執行查詢時,這個標記會使其返回關於在執行計劃中每一步的資訊,而不是真正完全的執行該語句。

它會返回一行或多行資訊,顯示出執行計劃中的每一部分和執行的次序。在查詢中,每個表的輸出只有一行,若多表關聯,則輸出多行。別名表單算為一個表,因此如果把表和自己連線,輸出中也會有兩行。這裡的表的定義非常的廣:可以是一個子查詢,一個 UNION 結果。

EXPLAIN有兩個變種:

  • EXPLAIN EXTENDED:看起來和正常的EXPLAIN行為一樣,但他會告訴伺服器“逆向編譯”執行計劃為一個 SELECT 語句(SHOW WARNINGS 後能看到),該命令在MySQL5.0之後可用,MySQL5.1開始還額外增加一個 filtered 列。
  • EXPLAIN PARTITIONS:如果查詢基於分割區表的話,將顯示查詢將存取的分割區。MySQL5.1以及更新的版本支援。

增加了EXPLAIN之後,MySQL可能仍然會執行部分查詢,如果查詢中FROM字句中包括子查詢,那麼MySQL實際會執行子查詢的,並將其結果放在一個臨時表中,然後完成外層查詢優化。

EXPLAIN 返回的只是個近似結果,並且還有相關是的限制:

  • 不會告訴你知道觸發器、儲存過程或 UDF 如何影響查詢。
  • 不支援儲存過程,儘管可以單獨抽取查詢進行 EXPLAIN。
  • 不會告訴你查詢執行中所做的特定優化。
  • 不會顯示關於查詢的執行計劃的所有資訊。
  • 無法區分具有相同名字的事物,例如,它對記憶體排序和臨時檔案排序都使用“filesort”,並且對磁碟上和記憶體中的臨時表都顯示“Using temporary”。
  • 可能會誤導,例如:可能會對一個很小的limit查詢顯示全索引掃描。
  • 只能解釋select查詢(5.6以後允許解釋非select語句),不會對儲存過程呼叫和INSERT、DELETE、UPDATE或其他語句做解釋,但可通過重寫某些非 SELECT 查詢以利用 EXPLAIN。

2 EXPLAIN中的列

2.1 id

一個編號,表示select所屬的行。如果查詢中沒有子查詢或關聯查詢,那麼只會有唯一的SELECT,每一行的該列中都將顯示一個1,否則,內層的SELECT語句一般會順序編號,對應於其在原始語句中的位置。id越大執行優先順序越高,id相同則認為是一組,從上往下執行,id為NULL最後執行。

例如UNION查詢中最後對於臨時表的查詢,它的id就為null,因為臨時表並不在原sql中出現。

EXPLAIN select * from contacts where contact_id <1000
UNION 
select * from contacts where contact_id >99000

2.2 select_type

表示對應行是簡單還是複雜的查詢。

  • SIMPLE,簡單SELECT,查詢不包括UNION和子查詢。
  • PRIMARY,查詢中若查詢包含任何複雜的子部分,最外層的select被標記為PRIMARY。

其他部分標記如下:

  • SUBQUERY,包含在SELECT子句(不在from子句中)中的子查詢的SELECT,結果不依賴於外部查詢。
  • DERIVED,包含在from子句中的子查詢中的SELECT。MySQL會遞迴執行並將結果存放在一個臨時表中,也稱為派生表,因為該臨時表是從子查詢中派生來的。
  • UNION,UNION中的第二個或後面的SELECT。第一個SELECT被標記就好像它以部分外查詢來執行,因此第一個SELECT可能顯示為PRIMARY。如果UNION被FROM字句中的子查詢包含,那麼它的第一個SELECT被標記為DERIVED。
  • UNION RESULT,用來從UNION的匿名臨時表中檢索結果的SELECT。

除了上面這些,SUBQUERY和UNION還可以被標記為DEPENDENT和UNCACHEABLE,DEPENDENT意味著SELECT 依賴與外層查詢中發現的資料;UNCACHEABLE意味著SELECT 中的某些特性阻止結果被快取於一個 Item_cache 中。

EXPLAIN select * from contacts where contact_id =99000

2.3 table

顯示了EXPLAIN對應行正在存取哪個表。通常情況下,它相當表明了:那就是那個表,或者該表的別名。

可以通過該列從上到下觀察MySQL的關聯優化器為查詢選擇的關聯順序。

from字句中有子查詢的時候,table列是<derivedN>的形式,N指向子查詢id,這裡N總是指向EXPLAIN輸出結果中的後面的一行。

當有UNION時,UNION RESULT的table列包含一個參與UNION的id列表,UNION RESULT總是出現在UNION中所有參與行之後,例如<union 1,2>

2.4 type

關聯型別,或者說存取型別,該欄位表明MySQL決定如何查詢表中的行。

常用的存取型別如下(效能依次從最差到最優):

  • ALL全表掃描,從頭到尾的查詢所需要的行。但仍然存在例外,例如使用了 LIMIT ,或者Extra 列中顯示 “Using distinct/not exists”。
  • index跟全表掃描一樣,只是MySQL掃描表時按照索引次序進行而不是行,主要優點是避免了排序;缺點是要承擔按索引次序讀取整個表的開銷。這通常意味著如實按照隨機次序存取行,開銷較大。如果Extra 列中顯示 “using index”,說明MySQL正在使用覆蓋索引,這樣就不需要按索引次序存取每一行資料,開小會少很多。
  • range範圍掃描,就是一個有限制的索引掃描,使用一個索引來檢索給定範圍的行,不需要遍歷全部索引。範圍掃描通常出現在between,>,<,>=等操作中。in()和OR也會顯示範圍掃描,但這兩者其實是不同的存取型別,效能上也有差異。此類查詢的開銷根ref索引存取的開銷相當。
  • ref索引存取,也叫索引查詢。返回所有匹配某個單個值的行,然而它可能會找到符合條件的多個行。此類索引存取只有當使用非唯一性索引或者唯一索引的非唯一性字首時才會發生。把他叫ref是因為他要和某個參考值相比較。這個參考值或者是一個常數,或者來自多表查詢前一個表裡的結果值。
  • eq_ref:使用這種索引查詢,MySQL清楚的知道最多隻返回一條符合條件的記錄,使用主鍵或者唯一值索引查詢時能看到這種方法。MySQL對於這種存取型別的優化做得非常好,因為它知道到無需估計匹配行的範文或者在找到匹配行後再繼續查詢(因為值不會重複)。
  • const,system當MySQL能對查詢的某部分進行優化並將其轉換成一個常數時,它就會使用這些存取型別。比如通過將某一行的主鍵存取WHERE字句的方式來查詢主鍵:SELECT id from t where id = 1。此時MySQL就能把這個查詢轉換為一個常數。
  • NULL這種存取方式意味著MySQ能在優化階段分解查詢語句,在執行階段甚至不需要再存取表或者索引。例如,從一個索引列裡選取最小值可以通過單獨查詢索引來完成,不需要在執行時存取表。
  • index_merge索引合併(index merge)。MySQL5.0之前,一個表一次只能使用一個索引,無法同時使用多個索引分別進行條件掃描。但是從5.1開始,引入了索引合併優化技術,對同一個表可以使用多個索引分別進行條件掃描,然後將它們各自的結果進行合併(intersect/union)。index merge使得我們可以使用到多個索引同時進行掃描,然後將結果進行合併。聽起來好像是很好的功能,但是如果出現了 index intersect merge,那麼一般同時也意味著我們的索引建立得不太合理,因為 index intersect merge 是可以通過建立複合索引進行更一步優化的。

2.5 possible_keys

顯示查詢可以使用哪些索引,這是基於查詢存取的列和使用的比較操作符來判斷的。該列表是在優化過程的早期建立的,因此列出來的索引對於後續實際優化過程可能是沒有用的。

2.6 key

顯示mysql決定採用哪一個索引來優化對該表的存取,如果該索引沒有出現在possible_keys列中,那麼MySQL選用它是出於另外的原因——例如,它可能選擇了一個覆蓋索引,哪怕它沒有WHERE字句。

possible_keys表示哪些索引有助於高效查詢,而key表示該索引可以最小化查詢成本。

如果沒有選擇索引,鍵是NULL。要想強制MySQL使用或忽視possible_keys列中的索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX

2.7 key_len

MySQL在索引中使用的位元組數,通過這個值可以算出具體使用了索引中的哪些列,計算時需要考慮字元集,如果欄位允許為 NULL,需要1位元組記錄是否為 NULL。

key_len顯示的值為索引欄位的最大可能長度,並非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的。

2.8 ref

這一列顯示了在key列記錄的索引中,表查詢值所用到的列或常數,即哪些列或常數被用於查詢索引列上的值。常見的有:const(常數),func,NULL,欄位名(例:film.id)

2.9 rows

這一列是mysql估計要讀取並檢測的行數,注意這個不是結果集裡的行數,而是MySQL為了找到符合查詢的每一個標準的那些行而必須讀取的行的平均數。

有時候該估值可能很不精確,該數位也反映不了LIMIT字句的真正檢查行數。

2.10 Extra

這一列展示的是額外資訊。常見的重要值如下:

  • Using index:表示MySQL將使用覆蓋索引,這發生在對錶的請求列都是同一索引的部分的時候,返回的列資料只使用了索引中的資訊,而沒有再去存取表中的行記錄。是效能高的表現。
  • Using index condition:在5.6版本後加入的新特性索引下推(Index Condition Pushdown,ICP),在索引遍歷過程中,對索引中包含的欄位先做判斷(即使該欄位沒有使用到索引),直接過濾掉不滿足條件的記錄,減少回表次數。
  • Using where:意味著MySQL伺服器將在儲存引擎檢索行後再進行過濾。就是先通過索引讀取整行資料,再按 WHRER條件進行檢查,符合就留下,不符合就丟棄。查詢的列未被索引覆蓋。
  • Using temporary:MySQL需要建立一張臨時表來中間結果並進一步處理,比如union、group by、distinct等,出現這種情況一般是要進行優化的,首先是想到用索引來優化。
  • Using filesort:MySQL會對結果使用一個外部索引排序,而不是按索引次序從表裡讀取行,即filesort(檔案排序)。此時mysql會根據聯接型別瀏覽所有符合條件的記錄,並儲存排序關鍵字和行指標,然後排序關鍵字並按順序檢索行資訊。這種情況下一般也是要考慮使用索引來優化的。filesort有兩種,一種是記憶體排序,一種是磁碟排序,無法得知。
  • Distinct: 一旦MySQL找到了與行相聯合匹配的行,就不再搜尋了,常見於關聯查詢。
  • No tables used:Query語句中使用from dual 或不含任何from子句。
  • Using join buffer:使用了連線快取,join語句用到了緩衝區。

到此這篇關於MySQL EXPLAIN執行計劃解析的文章就介紹到這了,更多相關MySQL EXPLAIN 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com