文章目錄
MySQL Query Optimizer簡介
- MySQL中有專門負責優化SELECT語句的優化器模塊, 主要功能 : 通過計算分析系統中收集到的統計信息, 爲客戶端請求的Query提供它認爲最優的執行計劃
- 當客戶端向MySQL請求一條Query, 命令解析器模塊完成請求分類, 區別出事SELECT並轉發給MySQL Query Optimizer時, MySQL Query Optimizer首先會對整條Query進行優化, 處理掉一些常量表達式的預算, 直接換算成常量值。並對Query中的查詢條件進行簡化和轉換, 如去掉一些無用而顯而易見的條件, 結構調整等。然後分析Query中的Hint信息(如果有), 看顯示Hint信息是否可以完全確定該Query的執行計劃。如果沒有Hint或Hint信息還不足以完全確定執行計劃, 則會讀取所涉及對象的統計信息, 根據Query進行相應的計算分析, 然後再得出最後的執行計劃。
MySQL常見瓶頸
- CPU : CPU在飽和的時候一般發生在數據裝入內存或從磁盤上讀取數據的時候
- IO : 磁盤I/O瓶頸發生裝入數據遠大於內存容量的時候
- 服務器硬件的性能瓶頸 : top, free, iostat和vmstat等命令來查看系統性能狀態
- 程序中SQL語句問題, Explain查看執行計劃
上面的三個問題一般會有對應的運維人員去處理, 作爲開發人員最需要關注的是SQL問題
覆蓋索引(Covering Index), 又稱爲索引覆蓋
這個概念下面需要用到,先放在這裏
- 理解方式一 : 就是SELECT的數據列只用從索引中就能夠取到, 不必讀取數據行, MySQL可以利用索引返回SELECT列表中的字段, 而不必根據索引再次讀取數據文件, 換句話說, 查詢列要被所建的索引覆蓋。
- 理解方式二 : 索引是高效找到行的一個方法, 但是一般數據庫也能使用索引找到一個列的數據, 因此它不必讀取整個行。畢竟索引的葉子節點存儲了它們索引的數據; 當能通過讀取索引就可以得到想要的數據, 那就不需要讀取行了。一個索引包含了(或覆蓋了)滿足查詢結果的數據就叫做覆蓋索引
注意 :
如果要使用覆蓋索引, 一定要注意SELECT列表中只取出需要的列, 不能SELECT *, 因爲如果將所有字段一起做索引會導致索引文件過大, 查詢性能下降。
執行計劃(Explain)詳解
簡介
使用EXPLAIN關鍵字可以模擬優化器執行SQL的查詢語句, 從而知道MySQL是如何處理你的SQL語句的。分析你的查詢語句或是表結構的性能瓶頸
Explain能得到哪些信息
- 表的讀取順序
- 數據讀取操作的操作類型
- 哪些索引可以使用
- 哪些索引被實際使用
- 表之間的引用
- 每張表有多少行被優化器查詢
使用方法
- explain + SQL語句
執行計劃包含的信息:
執行計劃信息詳解
id
select查詢的序列號, 包含一組數字, 表示查詢中執行select子句或操作表的順序
-
id相同 : 執行順序由上向下
-
id不同 : 如果是子查詢, id序號會遞增, id值越大, 優先級越高, 越先被執行
-
ID相同不同, 同時存在 : id如果相同.可以認爲是一組, 從上往下順序執行; 在所有組中, id值越大, 優先級越高, 越先執行
derived表示衍生, 第一行中的derived2表示, 這個虛表是由id爲2的語句所衍生的
select_type
查詢的類別, 主要用於區別普通查詢, 聯合查詢, 子查詢等複雜查詢
- SIMPLE : 簡單的select查詢, 查詢中不包含子查詢或者UNION
- PRIMARY : 查詢中包含任何負責的子查詢, 最外層查詢被標記爲PRIMARY
- SUBQUERY : 在SELECT或WHERE列表中包含子查詢
- DERIVED : 在FROM列表中包含的子查詢被標記爲DERIVED(衍生), MySQL會遞歸執行這些子查詢, 把結果放在臨時表裏
- UNION : 若第二個SELECT出現在UNION之後, 則被標記爲UNION; 若UNION包含在FROM子句的子查詢中, 外層SELECT被標記爲 : DERIVED
- UNION RESULT : 從UNION表獲取結果的SELECT
table
顯示這一行的數據是關於哪張表的
type
訪問類型, 顯示查詢使用了何種類型, 從最好到最差依次是 :
system>const>eq_ref>ref>range>index>ALL
一般來說, 要保證查詢至少達到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(全表掃描), 將遍歷全表以找到匹配的行
possible_keys, key
possible_keys :
顯示可能應用在這張表中的索引, 一個或多個。
查詢涉及到的字段是若存在索引, 則該索引將被列出, 但不一定被查詢實際使用
key :
實際使用的索引, 如果爲NULL, 則沒有使用索引。
查詢中若使用了覆蓋索引, 則該索引僅出現在key列表中
覆蓋索引演示 :
possible_keys,key演示 :
key_len
- 表示索引中使用的字節數, 可通過該列計算查詢中使用的索引的長度。在不損失精確性的情況下, 長度越短越好。
- key_len顯示的值爲索引字段的最大可能長度, 並非實際使用長度, 即key_len是根據表定義計算而得, 不是通過表內檢索獲得的
ref
顯示索引的哪一列被使用了, 如果可能的話, 最好是一個常數。哪些列或常量被用於查找索引列上的值
rows
根據表統計信息及索引選用情況, 大致估算出找到所需記錄所需要讀取的行數
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, 不能用來獲取任何數據, 如name=‘張三’ and name=‘李四’
-
SELECT tables optimized away : 在沒有group by子句的情況下, 基於索引優化MIN/MAx操作或者對於MyIsam存儲引擎優化COUNT(*)操作, 不必等到執行階段再進行計算, 查詢執行計劃生成階段即完成優化。
-
distinct : 優化distinct操作, 在找到第一匹配的元組後即停止找同樣值的動作