在MySQL的邏輯架構的第二層服務層中有一個優化器(Optimizer),該優化器能以它自己認可的一種方式優化底層MySQL的執行順序。使用EXPLAIN關鍵字可以模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理SQL語句的。分析查詢語句或是表結構的性能瓶頸。
MySQL常見瓶頸
MySQL的常見瓶頸分爲以下幾類:
- CPU:SQL中對大量數據進行比較、關聯、排序、分組(最大的壓力在於比較)
- IO:實例內存滿足不了緩存數據或排序等需要,導致產生大量物理 IO。查詢執行效率低,掃描過多數據行。
- 鎖:不適宜的鎖的設置,導致線程阻塞,性能下降。死鎖,線程之間交叉調用資源,導致死鎖,程序卡住。
- 服務器硬件的性能瓶頸:使用top,free, iostat和vmstat來查看系統的性能狀態
Explain
Explain用途
先簡單看一下Explain的用途,初次看下面羅列的幾點你可能並不知道在說啥,但通過接下來的學習,回過頭來看時就會明瞭了。
- 查看錶的讀取順序
- 哪些索引可以使用
- 數據讀取操作的操作類型
- 哪些索引被實際使用
- 表之間的引用
- 每張表有多少行被優化器查詢
Explain使用
語法: Expalin + 一條完整的SQL語句。
如:explain select * from dept;
注意:在5.7以前的版本中,想要顯示partitions需要使用explain partitions命令;想要顯示filtered需要使用explain extended命令。在5.7版本後,默認explain直接顯示partitions和filtered中的信息。
各字段含義
1. id
select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序。執行順序描述如下:id值相同時,執行順序由上至下;id值不同時,數字越大的越先執行
。
案例:查看下面的執行語句分析MySQL的執行順序。
EXPLAIN SELECT t2.* FROM t2, (SELECT * FROM t3 WHERE t3.content='') s3 WHERE s3.id=t2.id;
解釋:我們看id列,1,1,2三個數值,數字越大越先執行,2對應的表爲t3表,所以先讀取t3表,即執行(SELECT * FROM t3 WHERE t3.content=’ '),然後兩個1相同,則自上往下順序執行,先讀取derived2即有id爲2的衍生出的衍生表s3,最後再讀取t2表。(此圖爲5.5版本)
2. select_type
select_type用來指明查詢類型,可能的取值如下:
含義:
- simple:表示不需要union操作或者不包含子查詢的簡單select查詢。有連接查詢時,外層的查詢爲simple,且只有一個。
- primary:一個需要union操作或者含有子查詢的select,位於最外層的查詢即爲primary。且只有一個。
- union:union連接的select查詢,除了第一個表外,第二個及以後的表查詢都是union。
- dependent union:與union一樣,出現在union 或union all語句中,但是這個查詢要受到外部查詢的影響
- union result:包含union的結果集,在union和union all語句中,因爲它不需要參與查詢,所以id字段爲null
- subquery:除了from子句中包含的子查詢外,其他地方出現的子查詢都可能是subquery
- dependent subquery:與dependent union類似,表示這個subquery的查詢要受到外部表查詢的影響
- derived:from子句中出現的子查詢。
- materialized:被物化的子查詢
- UNCACHEABLE SUBQUERY:對於外層的主表,子查詢不可被物化,每次都需要計算(耗時操作)
- UNCACHEABLE UNION:UNION操作中,內層的不可被物化的子查詢(類似於UNCACHEABLE SUBQUERY)
3. table
表示這一行的數據是關於哪張表的,可以是真實的表名,也可以是衍生表,如< derived N>表示該表來自於某個查詢衍生出來的,後邊的N就是執行計劃中的id。<union M,N>表示這個結果來自於union查詢的id爲M,N的結果集。
4. partitions
版本5.7以前,該項是explain partitions顯示的選項,5.7以後成爲了默認選項。該列顯示的爲分區表命中的分區情況。非分區表該字段爲空(null)。
5. type
type是訪問類型,可能的取值按從好到壞的排序依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range(儘量保證) > index > ALL
需要記住的是:system>const>eq_ref>ref>range>index>ALL
一般來說,得保證查詢至少達到range級別,最好能達到ref級別
- system:表中只有一行數據,且只能用於myisam和memory表。如果是Innodb引擎表,type列在這個情況通常都是all或者index。這是const類型的特列,平時不會出現,這個也可以忽略不計。
- const:使用主鍵或者唯一索引(primary key 或者 unique key),只匹配一行數據,也叫做唯一索引掃描。
- eq_ref:唯一性索引掃描,對於每個索引鍵,表中
只有一條記錄
與之匹配。常見於主鍵或唯一索引掃描,如一個公司的CEO只有一個,對應的部門爲總裁辦,只有一條記錄與之對應。 - ref:非唯一性索引掃描,返回匹配某個單獨值的
所有行
。本質上也是一種索引訪問,它返回所有匹配某個單獨值的行,然而,它可能會找到多個符合條件的行,所以他應該屬於查找和掃描的混合體。 - range:只檢索給定範圍的行,索引範圍掃描,常見於使用 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()或者like等運算符的查詢中。
- index:Full Index Scan全索引掃描,index與ALL區別爲index類型只遍歷索引樹。這通常比ALL快,因爲索引文件通常比數據文件小。(也就是說雖然all和Index都是讀全表,但index是從索引中讀取的,而all是從硬盤中讀取的)
- all:Full Table Scan全表掃描,將遍歷全表以找到匹配的行
- index_merge:表示查詢使用了兩個及以上的索引,通常出現在有 or 的關鍵字的sql中
- ref_or_null:對於某個字段既需要關聯條件,也需要null值得情況下。查詢優化器會選擇用ref_or_null連接查詢。
例如:SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL; - unique_subquery:用於where中的in形式子查詢,子查詢返回不重複值唯一值
- index_subquery:用於in形式子查詢使用到了輔助索引或者in常數列表,子查詢可能返回重複值,可以使用索引將子查詢去重。
6. possible_keys
顯示可能應用在這張表中的索引,一個或多個。查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢實際使用
7.key
實際使用的索引。如果爲NULL,則沒有使用索引。查詢中若使用了覆蓋索引,則該索引和查詢的select字段重疊,顯示的key爲索引名稱。
8. key_len
表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度。key_len字段能夠幫你檢查是否充分的利用上了索引。key_len只計算where條件用到的索引長度,而排序和分組就算用到了索引,也不會計算到key_len中。
9. ref
顯示索引的哪一列被使用了,如果可能的話,是一個常數。哪些列或常量被用於查找索引列上的值。
10.rows
rows列顯示MySQL認爲它執行查詢時必須檢查的行數。估算出的行數值,不是精確值。行數越少越好。
11. filtered
使用explain extended時會出現這個列,5.7之後的版本默認就有這個字段,不需要使用explain extended了。這個字段表示存儲引擎返回的數據在server層過濾後,剩下多少滿足查詢的記錄數量的比例,注意是百分比,不是具體記錄數。
12. extra
包含不適合在其他列中顯示但十分重要的額外信息。
這一列可以顯示的信息有:
- using filesort:說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。
MySQL中無法利用索引完成的排序操作稱爲“文件排序”。 - using temporary:使用了臨時表保存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序
order by
和分組查詢group by
。 - using index:表示相應的select操作中使用了覆蓋索引(Covering Index),避免訪問了表的數據行,效率不錯!如果同時出現using where,表明索引被用來執行索引鍵值的查找;
如果沒有同時出現using where,表明索引只是用來讀取數據而非利用索引執行查找。 - using where:表明使用了where過濾
- using join buffer:使用了連接緩存
- impossible where:where子句的值總是false,不能用來獲取任何元組
注意:若出現上述紅色的提示信息,則需要對查詢語句進行相應的優化了。