MySQL Query Optimizer
MySQL Query Optimizer是MySQL中專門負責優化SELECT語句的模塊,其主要功能是:通過計算分析系統中收集到的統計信息,爲客戶端請求的Query提供MySQL認爲最優的執行計劃1。
優化器執行過程:
- 客戶端向MySQL發起Query請求;
- 命令解析器模塊完成請求分類,區別出SELECT並轉發給MySQL Query Optimizer(查詢優化器);
- 查詢優化器對整條Query進行優化,處理掉一些常量表達式的預算,直接換算成常量值;
- 查詢優化器對Query中的查詢條件進行簡化和轉換,如去掉一些無用或顯而易見的條件、結構調整等;
- 分析Query中是否有Hint消息,是否可以通過Hint信息完全確定該Query的執行計劃;
- 若沒有Hint信息或不足以完全確定執行計劃,則會讀取所涉及對象的統計信息,根據Query進行寫相應的計算分析,得出最後的執行計劃。
查看執行計劃:Explain
Explain的作用
使用EXPLAIN關鍵字可以通過模擬優化器執行SQL查詢語句瞭解MySQL是如何處理SQL語句,從而分析查詢語句或是表結構中的性能瓶頸。
使用Explain可以瞭解到:
- 表的讀取順序:通過執行計劃中的id判斷
- 數據讀取操作的操作類型:通過執行計劃中的select_type判斷
- 哪些索引可以使用:通過執行計劃中的possible_keys判斷
- 哪些索引被實際使用:通過執行計劃中的key判斷
- 表之間的引用:通過執行計劃中的ref判斷
- 每張表有多少行被優化器查詢:通過執行計劃中的rows判斷
Explain的使用
基本語法:Explain + SQL語句2
執行計劃包含的信息:
- id:select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序
- id相同:執行順序由上而下
- id不同:如果是子查詢,id的序號會遞增,id值越大,優先級越高,越先被執行
- id相同、不同同時存在:相同的id視爲一組,組內從上往下順序執行,在所有id組中,id值越大,優先級越高,越先被執行
- id相同:執行順序由上而下
- select_type:操作類型
- SIMPLE:不包含子查詢或者UNION的簡單查詢
- PRIMARY:包含任何子查詢的查詢中最外層查詢(即最後加載的查詢)
- SUBQUERY:在SELECT子句或者WHERE子句中的子查詢
- DERIVED3:FROM子句中的子查詢(若包含UNION,則外層查詢將被標記爲DERIVED)
- UNION:UNION後的查詢
- UNION RESULT:UNION連接的查詢合併後的結果集
- table:數據查詢基於的數據表
- patitions:分區表命中的分區情況,非分區表該字段爲Null
- type:訪問類型,常見的類型從好到壞的順序是system>const>eq_ref>ref>range>index>ALL,一般來說,保證查詢至少能夠達到range級別,最好能達到ref級別
- ALL:全表掃描,百萬級別以上數據量的需要優化;
- index:全索引掃描,掃描只會遍歷索引樹,相較於ALL從硬盤中讀取全表數據,index掃描是從索引中讀取全表數據,由於索引文件通常比數據文件小,使得index掃描比ALL掃描快;
- range:索引範圍掃描,返回索引在給定範圍的匹配行;
- ref:非唯一性索引掃描,多表聯結查詢匹配某個單獨值的結果可能爲多個匹配行;
- eq_ref:唯一性索引掃描,多表聯結查詢匹配某個單獨值的結果只有一個匹配行4,通常是將主鍵或唯一索引與聯結的前表中的列進行比較;
- const:唯一性索引掃描,單表查詢結果最多隻有一個匹配行,通常是將primary key或unique索引的所有部分與常量值進行比較;
- system:表只有一行記錄(等於系統表),這是const類型的特里,可以忽略不考慮。
- possible_keys:顯示可能應用在表查詢中的所有索引,即查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被實際使用
- key:實際使用的索引,如果爲NULL,則沒有創建索引,或者創建了索引但未使用
- key_len:表示索引中使用的字節數,可以通過該列計算查詢中使用的索引的長度,即索引字段的最大可能長度,並非實際使用長度。在不損失精確性的情況下,長度越短越好。
- ref:表示被用於與索引比較的常量或列
- rows:表示根據表統計信息及索引選用情況,大致估算出檢索所需要讀取的行數,行數越少越好
- filtered:存儲引擎返回的數據在server層過濾後,剩下滿足查詢的記錄數量的比例(%)
- extra:表示包含不適合在其他列中顯示但十分重要的信息
- using filesort:表示查詢和排序的字段與索引不符(引用的字段個數和順序不符),MySQL無法利用索引完成排序操作,會影響查詢的性能,儘量優化消除。如下圖,索引爲empno,而排序字段爲sal,此時索引的排序功能不再起作用;
- Using temporary:表示MySQL在對查詢結果排序時使用保存了中間結果的臨時表,常見於order by和group by,會嚴重影響查詢的性能;
- Using Index:表示相應的查詢操作中使用了覆蓋索引5,避免訪問了表的數據行
- 存在using where:表明索引被用來執行索引鍵值的查找
- 不存在using where:表明索引用來讀取數據而非執行查找動作
- 存在using where:表明索引被用來執行索引鍵值的查找
- Using where:表示使用了where過濾
- Using index condition:表示相應的查詢操作中同時使用創建了索引的列和未創建索引的列,5.6版本後加入的新特性
- 存在Using where:表示未創建索引的列出現在WHERE子句中(emp表中對deptno、comm、sal三列創建了複合索引)
- 不存在Using where:表示未創建索引的列出現在SELECT子句中(emp表中對deptno、comm、sal三列創建了複合索引)
- 存在Using where:表示未創建索引的列出現在WHERE子句中(emp表中對deptno、comm、sal三列創建了複合索引)
- Using join buffer:表示使用了聯結緩存,join聯結使用的比較多,建議增大緩存
- Impossible where:WHERE子句的值總是false,不能獲取到任何數據結果
- using filesort:表示查詢和排序的字段與索引不符(引用的字段個數和順序不符),MySQL無法利用索引完成排序操作,會影響查詢的性能,儘量優化消除。如下圖,索引爲empno,而排序字段爲sal,此時索引的排序功能不再起作用;
MySQL認爲最優的數據檢索方式,不意味着就是DBA認爲的最優的數據檢索方式,這部分認知的差異往往容易耗費時間。 ↩︎
本文中使用的數據表是Oracle自帶的scott用戶的數據表的MySQL副本,所以不另外提供建表語句 ↩︎
MySQL會遞歸執行這部分查詢,並把結果放在臨時表裏,即使這樣會增加服務器負擔。 ↩︎
官網原文:One row is read from this table for each combination of rows from the previous tables. ↩︎
覆蓋索引(Covering Index):查詢的數據列只需要從索引中就可以獲取,不需要讀取數據行,即一個索引包含了滿足查詢結果的數據列 ↩︎