explAIn關鍵字可以模擬優化器執行 SQL 查詢語句,從而知道 MySQL 是如何處理 SQL 語句的。分析查詢語句或表結構的性能瓶頸。執行語句:explain + SQL語句。表頭信息如下:
explain各個字段代表的意思
- id :select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序。
- select_type :查詢類型 或者是 其他操作類型。
- table :正在訪問哪個表。
- partitions :匹配的分區。
- type :訪問的類型。
- possible_keys :顯示可能應用在這張表中的索引,一個或多個,但不一定實際使用到。
- key :實際使用到的索引,如果為NULL,則沒有使用索引。
- key_len :表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度。
- ref :顯示索引的哪一列被使用了,如果可能的話,是一個常數,哪些列或常量被用于查找索引列上的值。
- rows :根據表統計信息及索引選用情況,大致估算出找到所需的記錄所需讀取的行數。
- filtered :查詢的表行占表的百分比。
- Extra :包含不適合在其它列中顯示但十分重要的額外信息。
ID 字段
select 查詢的序列號,包含一組數字,表示查詢中執行 select 子句或操作表的順序。三種情況:
id 相同: 執行順序由上而下:
explain select t2.* from t1,t2,t3 where t1.id = t2.id and t1.id = t3.id and t1.other_column = '';
- 1.
id 不同: 如果是子查詢,id 序號會遞增,id 越大優先級越高,越先被執行。
explain select t2.* from t2 where id = (select id from t1 where id = (select t3.id from t3 where t3.other_column = ''));
- 1.
id 相同不同同時存在: id 如果相同,可以認為是一組,由上往下執行;在所有組里 id 越大,優先級越高,越先執行。
explain select t2.* from (select t3.id from t3 where t3.other_column = '') s1,t2 where s1.id = t2.id;
- 1.
select_type 字段
主要用于區別普通查詢、聯合查詢、子查詢等的復雜程度。
SIMPLE: 簡單的 select 查詢,查詢中不包含子查詢或者 UNION。
PRIMARY: 查詢中若包含任何復雜的自查詢,最外層查詢為 PRIMARY。
SUBQUERY: 在 SELECT 或 WHERE 中包含子查詢。
UNCACHEABLE SUBQUERY:一個子查詢的結果不能被緩存,必須重新評估外鏈接的第一行。
DERIVED: 在 FROM 列表中包含的子查詢被標記為 DERIVED(衍生)MySQL 會遞歸執行這些子查詢,把結果放進臨時表。
UNION: 若第二個 SELECT 出現在 UNION 之后,則被標記為 UNION,若 UNION 包含在 FROM 子句的子查詢,則外層SELECT 將被標記為 DERIVED。
UNION RESULT: 從 UNION表中獲取結果的 SELECT。
table字段
顯示這行數據是關于那張表
type字段
首先說一下這個字段,要記住以下10個狀態,(從左往右,越靠左邊的越優秀)
NULL > system > const > eq_ref > ref > ref_or_null > index_merge > range > index > ALL
- 1.
NULL
MySQL能夠在優化階段分解查詢語句,在執行階段用不著再訪問表或索引。存在這樣一種情況,大家都知道索引是將數據在B+Tree中進行排序了,所以你的查詢速率才這么高,那么B+樹的最邊上的葉子節點是不是要么是最大值要么是最小值啊?既然你都知道了,那MySQL比你更知道啊!當你要查詢最大值或者最小值時,MySQL會直接到你的索引得分葉子節點上直接拿,所以不用訪問表或者索引。
NULL的前提是你已經建立了索引。
SYSTEM
表只有一行記錄(等于系統表),這是const類型的特列,平時不大會出現,可以忽略。
const
表示通過索引一次就能找到,const用于比較 primary和 unique索引。因為只匹配一行數據,所以很快。
簡單來說,const是直接按主鍵或唯一鍵讀取。
eq_ref
用于聯表查詢的情況,按聯表的主鍵或唯一鍵聯合查詢。多表join時,對于來自前面表的每一行,在當前表中只能找到一行。這可能是除了system和const之外最好的類型。
ref 可以用于單表掃描或者連接。如果是連接的話,驅動表的一條記錄能夠在被驅動表中通過非唯一(主鍵)屬性所在索引中匹配多行數據,或者是在單表查詢的時候通過非唯一(主鍵)屬性所在索引中查到一行數據。
ref_or_null 類似ref,但是可以搜索值為NULL的行。
index_merge
表示查詢使用了兩個以上的索引,最后取交集或者并集,常見and ,or的條件使用了不同的索引,官方排序這個在ref_or_null之后,但是實際上由于要讀取多個索引,性能可能大部分時間都不如range。
range
只檢索給定范圍的行,使用一個索引來選擇行。一般where語句中出現between、<、>、in等的查詢。這種范圍掃描索引比全表掃描要好,因為只需開始索引的某一點,而結束另一點,不用掃描全部索引;
index
Full Index Scan,index與 ALL區別為 index類型只遍歷索引樹,索引文件通常比數據文件小。index從索引中讀取,而All是從硬盤讀取;
ALL
從磁盤中讀取;如果一個查詢的type是All,并且表的數據量很大,那么請解決它!!!
possible_keys字段
這個表里面存在且可能會被使用的索引,可能會在這個字段下面出現,但是一般都以key為準。
key字段
實際使用的索引,如果為null,則沒有使用索引,否則會顯示你使用了哪些索引,查詢中若使用了覆蓋索引(查詢的列剛好是索引),則該索引僅出現在key列表。
ref字段
列與索引的比較,表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值。
rows字段和Filter字段
rows是根據表的統計信息和索引的選用情況,優化器大概幫你估算出你執行這行函數所需要查詢的行數。
Filter是查詢的行數與總行數的比值。其實作用與rows差不多,都是數值越小,效率越高。
Extra字段
Using index
表示相應的 select操作中使用了覆蓋索引(convering index),避免訪問了表的數據行,效率不錯!
覆蓋索引(covering index ,或稱為索引覆蓋)即從非主鍵索引中就能查到的記錄,而不需要查詢主鍵索引中的記錄,避免了回表的產生減少了樹的搜索次數,顯著提升性能。
Using temporary
表示MySQL需要使用臨時表來存儲結果集,常見于排序 order by和分組查詢 group by。
Using fileSort
表示當SQL中有一個地方需要對一些數據進行排序的時候,優化器找不到能夠使用的索引,所以只能使用外部的索引排序。
MySQL無法利用索引完成的排序操作稱為“文件排序”。導致該問題的原因一般是Where條件和order by子句作用在了不同的列上,一般可以通過合適的索引來減少或者避免。(出現表示不好)
上面提到的常見情況,SQL語句通常寫成這樣select * from a where type = 5 order by id,這類語句一般會產生Using filesort這個選項,即使你在type和id上分別添加了索引。我們想一下它的工作過程,先根據type的索引從所有數據信息中挑選出滿足type = 5條件的,然后根據id列的索引信息對挑選的數據進行排序,所以產生了Using filesort選項。可以通過聯合索引解決這個問題,即在type, id兩列上建立一個聯合索引。
Using where
查詢的列未被索引覆蓋,where篩選條件非索引的前導列,Extra 中為 Using where。
所謂前導列,就是在創建復合索引語句的第一列或者連續的多列。比如通過:CREATE INDEX comp_ind ON table1(x, y, z)創建索引,那么x,xy,xyz都是前導列,而yz,y,z這樣的就不是。
using where,using index
查詢的列被索引覆蓋,并且 where篩選條件是索引列之一但是不是索引的前導列,Extra中為Using where; Using index,意味著無法直接通過索引查找來查詢到符合條件的數據;
查詢的列被索引覆蓋,并且where篩選條件是索引列前導列的一個范圍,同樣意味著無法直接通過索引查詢到符合條件的數據
Using index condition
查詢的列不全在索引中,where條件中是一個前導列的范圍
查詢列不完全被索引覆蓋,查詢條件完全可以使用到索引(進行索引查找)
NULL(既沒有Using index,也沒有Using where Using index,也沒有using where)。
查詢的列未被索引覆蓋,并且where篩選條件是索引的前導列,意味著用到了索引,但是部分字段未被索引覆蓋,必須通過“回表”來實現,不是純粹地用到了索引,也不是完全沒用到索引,Extra中為NULL(沒有信息)。
Using join buffer
使用了連接緩存。
小表驅動大表
在表連接過程中。一般選擇小表作為驅動表,大表作為被驅動表。
驅動表(小表)的連接字段無論建立沒建立索引都需要全表掃描的。被驅動表(大表)如果在連接字段建立了索引,則可以走索引。如果沒有建立索引則也需要全表掃描。
兩張表連接的情況
被驅動表的連接字段有索引:主鍵索引
對于驅動表中的每一條數據,到被驅動表的聚簇索引上尋找其對應的數據。
被驅動表的連接字段有索引:二級索引
對于驅動表上的每一條數據,到被驅動表的二次索引上尋找其對應的數據id,然后再根據數據id到聚簇索引上尋找對應的數據。
被驅動表的連接字段沒有索引
對于驅動表上的每一條數據,都要到被驅動表上進行一次全表遍歷,找到對應的數據。
join buffer的作用
就是針對被驅動表的連接字段沒有索引的情況下需要進行全表掃描,所以引入了join buffer內存緩沖區來對這個全表掃描過程進行優化。
impossible where
where子句總是false,不能用來獲取任何元素。即篩選條件沒能篩選出任何數據。
select tables optimized away
在沒有 GROUPBY 子句的情況下,基于索引優化 MIN/MAX操作。
distinct
優化 distinct操作。在找到第一匹配的時候就停止找同樣的動作。