explain執行計划:
-
通過使用explain關鍵字可以模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的。分析你的查詢語句或是表屬性瓶頸。
-
通過explain + SQL語句:
表的讀取順序 數據讀取操作的類型 哪些索引可以使用 哪些索引被實際使用 表之間引用 每張表有多少行被優化
1.id
- 通過id值可以知道sql語句執行順序:
id不同:如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
id有相同有不同:
-
情況1:id相同:

id 相同,執行順序由上至下執行 -
情況2:id有不同:

如果是子查詢,id的序號會遞增,id值越大優先級越高,越被執行。所以上例id=3先被執行,type=ALL做的是一個全表掃描 -
情況3:id有相同,有不同的:

id 如果相同,可以認為是一組,從上至下順序執行 在所有組中,id值越大,優先級越高,越先執行
2.select_type
-
根據此字段可以看到當前查詢類型,select_type常用值:
SIMPLE 簡單的select查詢,查詢中不包含子查詢或者UNION PRIMARY 查詢中若包含任何復雜的子部分,最外層查詢標記 SUBQUERY 在SELECT或WHERE列表中包含了子查詢 DERIVED 在FROM列表中包含的子查詢被標記為DERIVED(衍生),MySQL會遞歸執行這些子查詢,把結果放在臨時表 UNION 若第二個SELECT出現在UNION之后,則被標記為UNION,若UNION包含在FROM子句的子查詢中,外層SELECT將被標記為:DERIVED UNION RESULT 從UNION表獲取結果的SELECT
3.table
-
顯示這一行數據是關於哪一個表查詢。
derived 臨時表
4.type
- 表示訪問類型,訪問類型理論上如下表,排序越靠前性能越好:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
- 但我們工作中常接觸到:ALL,index,rang,ref,eq_ref,const,system,NULL
顯示查詢使用類型從最好到最差依次:
system>const>eq_ref>ref>range>index>ALL
-
一般來說,你的SQL語句至少得保證達到range級別,最好達到ref。
-
各類型解釋:
system :表只有一行(等於系統表)這是const類型的特列,平時不會出現,這個也可以忽略不計
const: 表示通過索引一次就找到了,const用於比較primary key或unique索引,因為只匹配一行數據,所以很快如將主鍵放置於where列表中,MySQL就能將該查詢轉換為一個常量。
eq_ref : 唯一性索引掃描,對於每個索引建,表中只有一條記錄與之匹配,常見於主鍵或唯一索引的掃描
ref : 非唯一性索引掃描,返回匹配某個單獨值的所有行,本質上也是一種索引訪問。它返回所有匹配某個單獨值的行,然而它可能會找到多個符合條件的行,所以它應該屬於查找和掃描的混合體。(工作中能達到這個就很牛逼了)
range : 只檢索給定范圍的行,使用一個索引來選擇行,key列顯示使用了哪個索引,一般就在你的where語句中出現between,<,>,in等的查詢,這種范圍掃描索引掃描比全表掃描要好,因為它只需要開始於索引的某一點,而結束語另一點,不用掃描全部索引。
index: Full Index Scan,index與ALL區別為index類型只遍歷索引樹,這通常比ALL快,因為索引文件通常比數據文件小,(也就是說雖然all和Index都是讀全表,但index是從索引中讀取的,而all是從硬盤中讀取)
all : Full Table Scan,將遍歷全表以找到匹配的行。
5.possible_keys 和 key
- 用於判斷是否使用索引,是否索引失效,你的sql是使用哪個索引。
possible_keys 顯示可能應用在這張表中的索引,一個或多個
查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢實際使用。
key 實際使用的索引,如果為NULL 則沒有使用索引。查詢中若使用了覆蓋索引,則該索引僅出現在key列表中,優先使用普通索引,然后使用主鍵索引
-
當然一般情況下都是出現理論索引,再看有沒有實際用到索引,但個別情況下也會出現理論上沒有索引,實際上使用覆蓋索引:

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

- 同樣查詢結果,精度越小,key_len越小,查詢效果越好。
7.ref
- 顯示索引的哪一列被使用了,如果可能的話,是一個常量,哪些列被用於查找索引列上的值。

8.rows
-
根據表統計信息及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數。

上圖,可以看到建立索引和沒有建立索引所掃描行數區別。
9.Extra
-
額外信息,它的顯示十分重要。
-
Using filesort (九死一生)

-
通過如下改進性能:

說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取,MySQL中無法利用索引完成的排序操作成為“文件排序”。(出現這個就代表SQL不好) -
Using temporay (十死無生)
新建了內部臨時表,保存中間結果,MySQL在對查詢結果排序使用臨時表,常見於order by 和分組查詢 group by,因創建臨時表大大降低了性能。

-
優化改進:

-
Using index
-
表示相應的select操作中使用了覆蓋索引,避免訪問了表的數據行,效率不錯!如果同時出現using where,表明索引被用來執行索引鍵值查找。如果沒有同時出現using where ,表示索引用來讀取數據而非執行查找動作。


-
Using where
- 使用了where過濾
-
Using join buffer
- 使用了連接緩存
-
impossible where
-
where子句值總是false,不能用來獲取任何元組
-
select查詢錯亂了。
當你執行name即等於July又等於z3導致SQL混亂: explain select * from staffs where name='July' and name='z3';
-
-
select tables optimized away
- 在沒有GROUPBY 子句的情況下,基於索引優化MIN/MAX操作或者對於MyISAM存儲引擎優化COUNT(*)操作,不必等到執行階段再進行計算,查詢執行計划生成的階段即完成優化。
-
dictinct
- 優化distinct操作,在找到第一匹配的元組后即停止找同樣值的動作。
覆蓋索引
覆蓋索引:可以簡單認為查詢列被所建的索引覆蓋。
也就是select數據列只從索引中就能夠取得,不必讀取數據行,MySQL可以利用索引返回select列表中的字段,而不必根據索引再次讀取數據文件。
-
請根據下面執行計划說出執行順序:


