1. 程式人生 > >MySQL系列-優化之explain執行計劃詳解

MySQL系列-優化之explain執行計劃詳解

1.id介紹

這個id不是主鍵的意思,他是用來標識select查詢的序列號,包含一組數字,表示查詢中執行select子句或者操作表的順序。

會出現以下情況:

id相同:按從上到下順序執行

id不同:id值越大,優先順序越高,越先被執行

id相同不同的同時存在:優先執行id值大的,如果id值相同,則按從上到下的順序執行

id為null表示是用來合併結果集的,在sql使用union關鍵字合併結果集就會出現他。

2.select_type介紹

顧名思義,表示查詢的型別

型別 說明
simple 簡單子查詢,不包含子查詢和union
primary 包含union或者子查詢,最外層的部分標記為primary
subquery 一般子查詢中的子查詢被標記為subquery,也就是位於select列表中的查詢
derived 派生表——該臨時表是從子查詢派生出來的,位於form中的子查詢
union 位於union中第二個及其以後的子查詢被標記為union,第一個就被標記為primary如果是union位於from中則標記為derived
union result 用來從匿名臨時表裡檢索結果的select被標記為union result
dependent union 顧名思義,首先需要滿足UNION的條件,及UNION中第二個以及後面的SELECT語句,同時該語句依賴外部的查詢
subquery 子查詢中第一個SELECT語句
dependent subquery 和DEPENDENT UNION相對UNION一樣

3.table介紹

對應行正在訪問哪一個表,表名或者別名。也有可能是臨時表等等,或者是union合併結果集。

  • 表名是derivedN的形式,表示使用了id為N的查詢產生的衍生表
  • 當有union result的時候,表名是union n1,n2等的形式,n1,n2表示參與union的id

注意:MySQL對待這些表和普通表一樣,但是這些“臨時表”是沒有任何索引的。

4.舉例說明

說明:可以看到,先查詢b2表再查詢b1表,而且都是簡單查詢。

說明:b2表對應的id為2,所以先查詢b2表,查詢型別是依賴子查詢,然後在查詢b1表,查詢型別是主查詢。

說明:先查詢b2表,在查詢b3表,然後查詢b1表,最後合併結果集。<union1,2>指的是將id為1和id為2查詢的結果合併。

說明:先查詢b1表得出一個臨時表,然後在查詢這個臨時表,這個derived2表示使用了id為2的查詢出來的結果集作為臨時表,最後才是b2表。

5.type介紹

type意味著型別,這裡的type官方全稱是“join type”,意思是“連線型別”,這樣很容易給人一種錯覺覺得必須需要倆個表以上才有連線型別,稱之為訪問型別更加容易理解。訪問型別表示我們是以何種方式去訪問我們的資料的,當然很容易想的的是全表掃描了,直接暴力的遍歷一張表取尋找需要的資料,效率非常之低下。訪問型別的種類有很多,而且各個版本的MySQL可能會不一樣,但是常見的就那麼幾種,按照效率最差到最好依次排列依次是:

all < index < range < index_subquery < unique_subquery < index_merge < ref_or_null < ref < eq_ref < const<system

all : 這個就是全表掃描了,一般這樣的出現這樣的SQL而且資料量比較大的話那麼就需要進行優化了,要麼是這條SQL沒有用上索引,要麼是沒有建立合適的索引。

index : 全索引掃描,這個比all效率要好一點,主要有幾種情況,一是當前的查詢是覆蓋索引的,即我們需要的資料在索引中就可以獲取(Extra中有Using Index,Extra也是explain的一個欄位)(關於覆蓋索引:MySQL系列-優化之覆蓋索引),或者是使用了索引進行排序,這樣就避免資料的重排序(extra中無 Using Index)。如果Extra中Using Index與Using Where同時出現的話,則是利用索引查詢鍵值的意思。

range : 這個是index了範圍限制,例如 >100、<1000之類的查詢條件,這樣避免的index的全索引掃描,當然限制的範圍越小 效率就越高。

index_subquery : 在 某 些 IN 查 詢 中 使 用 此 種 類 型 , 與 unique_subquery 類似,但是查詢的是非唯一 性索引

unique_subquery : 在某些 IN 查詢中使用此種類型,而不是常規的 ref

index_merge : 說明索引合併優化被使用了

ref_or_null : 如同 ref, 但是 MySQL 必須在初次查詢的結果 裡找出 null 條目,然後進行二次查詢。

ref : 使用了非唯一性索引進行資料的查詢,例如:我們對使用者表的使用者名稱這一列建立了非唯一索引,因為使用者名稱可以重複,當我們查詢使用者的時候select * from user where username=“xxx”的時候就出現了ref,使用非唯一索引查詢資料。

eq_ref : 這個就很好理解了,使用的唯一性索引進行資料查詢,例如主鍵索引之類的。

const : 通常情況下,將一個主鍵放置到where後面作為條件查詢,mysql優化器就能把這次查詢優化轉化為一個常量,如何轉化以及何時轉化,這個取決於優化器。這個比eq_ref效率高一點。

system : 表只有一行。不過這種情況下就沒意義了。

NULL : MySQL不用訪問表或者索引就直接能到結果。

6.舉例說明

可以看到,有三個欄位,其中id是主鍵索引,n1是非唯一索引,n2是唯一索引。

select * from tb1; 簡單粗暴的全表掃描

查詢資料n1的時候使用了覆蓋索引。

使用n1列的索引進行排序,所以extra中沒有出現using index,因為當前查詢不是索引覆蓋的。這裡我強制使用了idx_n1,MySQL也遵循了我的建議(如果強制使用的索引是用不上的話,MySQL會忽略)。

很明顯,id>3,只需要範圍掃描。

n1是非唯一索引,所以type為ref。

n2這一列是唯一索引,MySQL直接把他優化到了const級別。

接下來的就不列舉了,因為在開發中能優化到range就很不錯了,而且有些情況因為業務的關係根本就不能優化。

7.possible_keys介紹

這個顯示可能用到的索引,一個列上可能有多個複合索引,但最後只能選擇其中一個使用。當然很可能一個都不會使用,也可能顯示沒有可能用上的索引,但最後卻用上了某個索引,所以這個possible_keys沒什麼太大意義。

8.key

這個就真實的反應了MySQL使用了哪個索引。這個欄位很關鍵,因為MySQL優化器的能力有限,有時候他使用的索引不一定是最優的,所以我們需要知道他到底使用了那個索引,以及強制MySQL使用某個DBA認為最優的索引。當然如果當前的查詢是覆蓋索引的話,這個索引也會出現在key中。

9.key_len介紹

他表示索引中使用的位元組數,可通過該key_len計算查詢中使用的索引長度,當然在不損失精度的情況下長度越短越好。但是這個key_len只是表示使用索引的長度最大可能是多少,並不是真實的長度。

10.舉例說明

對n1和n2欄位建立一個複合索引

可以看到,possible_key是null,實際使用了索引idx_n1n2,索引長度為1536,並且是覆蓋索引。

那如果我們強制使用索引idx_n1呢?

可以看到,key_len變短了,同時也從覆蓋索引變成了非覆蓋索引。

11.ref介紹

顯示索引的哪一列被使用了,如果可能的話,是一個常數。

12.rows介紹

根據表的統計資訊及索引使用情況,大致估算出找出所需的記錄需要讀取的行數。這個rows非常重要,直接反應的SQL找了多少資料,從前面的舉例說明中我們也可以看到,在完成目的的情況下當然是越少越好。這個更SQL使用的索引息息相關,可見索引的重要性。

13.extra介紹

這個是包含了一些十分重要的額外資訊,也是非常重要的一個欄位。

他可能包含以下一個或多個值:

1、using filesort,這個說明mysql無法利用索引進行排序,那他只能用排序演算法重新進行排序了,這會額外消耗資源。出現這個的話那麼說明這條SQL需要優化了,需要正確使用索引或者建立合適的索引。

下面是一個讓MySQL使用正確索引的例子,同樣的結果,不一樣的過程。

但是具體那條SQL更快呢,也不一定,根據具體情況而定,比如資料規模之類的。還有就是開發當中一般是不允許用select * 的,要什麼欄位就拿什麼欄位,不然會造成效能浪費。

2、using temporary,建立了臨時表來儲存中間結果,查詢完成之後又要把臨時表刪除。出現這樣的情況說明這條SQL語句請一定要優化,如果這樣的SQL一多的話非常影響系統的效能。

3、using index,前面也說過,這個表示當前的查詢是覆蓋索引的,直接從索引中讀取資料,而不用訪問資料表。如果同時出現using where表明索引被用來執行索引鍵值的查詢,如果沒有using where,表面索引被用來讀取資料,而不是進行查詢。

4、using where,使用了where進行條件過濾。

5、using join buffer、表示使用了連線快取。

6、impossible where,where語句的值總是false。

7、Distinct,一旦MySQL找到了與行相聯合匹配的行,就不再搜尋了。

14.重點

type:訪問型別,檢視SQL到底是以何種型別訪問資料的。

key:使用的索引,MySQL用了哪個索引,有時候MySQL用的索引不是最好的,需要force index()。

rows:最大掃描的列數。

extra:重要的額外資訊,特別注意損耗效能的兩個情況,using filesort和using temporary。

參考資料:

穀粒學院