天天看點

MySQL之SQL分析三部曲

在倒騰DB的時候,SQL會占據非常大的一部分時間,遇到執行效率不高的SQL時,就需要想辦法找到執行效率不高的原因,這裡簡單記錄分析SQL的三個步驟~

使用的資料庫版本為MySQL-5.7.7-rc

-----------------------------------------------------------------------------------------正文------------------------------------------------------------------------------------------

Step1,使用explain or explain extended來檢視MySQL的執行計劃,

extended在後續的版本會被取消,是以加不加沒什麼太大的關系,因為在MySQL-5.7.7-rc裡面,普通的explain已經有filter了,

個人了解:filter當做是過濾百分比,大體上就是找到最終結果需要掃描多少資料,基本上,低一些會比較好。

explain在網上有很多的介紹,這了解略過吧,基本上,在Extra列裡面,盡可能不要出現Use Temporary Table 和 Using file sort,相比較而言,使用臨時表的影響更大,file sort會小一些。

為什麼SQL的分析不在這裡就打住了?

原因很簡單,MySQL在優化查詢的時候是隻用一個索引的,是以在有些情況下,SQL查詢既存在排序,又存在比較複雜的where條件,那麼到底是用索引提高where條件的篩選效率?還是用索引去省掉排序的開銷?(優化器?MySQL的查詢優化器出了名的拙計,而且除了優化器本身的一切缺陷導緻Cost計算不準确以外,MySQL本身也會根據一些參數的設定去調整優化器的政策,而這些參數大多數時候我們并不了解)

Step2,當explain搞不定的時候,就需要profile來幫忙了,這個東西可以詳細的列出在每一個步驟消耗的時間,前提是先執行一遍語句。

profile預設是關閉的,是以需要在client先打開,操作如下圖

MySQL之SQL分析三部曲

在實際的生産環境中,可能會需要加大profile的隊列,保證想要檢視的語句耗時結果還儲存着,是以可以用如下操作來增加profile的隊列大小

MySQL之SQL分析三部曲

到這一步,profile的功能就已經打開了,這裡簡單試一下SQL語句,explain一下

MySQL之SQL分析三部曲

顯然這種語句是不合格的,那麼在優化前,可以看看這條語句的耗時,先執行以下select,然後show profiles檢視隊列的内容,

MySQL之SQL分析三部曲

可以看到ID為7的那一行正式執行過的語句,這時候使用show profile block io,cpu for query 7來檢視統計資訊(紅色為常用選項,可以不加的~)

MySQL之SQL分析三部曲

紅色方框标出來了兩行内容,Creating sort index消耗了接近99%的時間,說明這個查詢的大部分時間消耗在了排序階段

Sending data标出來是要特别注意一下,并不隻是在伺服器端和用戶端之間sending data,還包括了從磁盤讀取資料的時間,是以對大表執行全表掃描or索引的效率不高時,這個時間會比較高

找到了主要耗時的部分,那麼就建立一個索引,再來看看profile的資料

MySQL之SQL分析三部曲

然而即便是analyze table以後,優化器依然不選擇走索引,而是堅持全表掃描來執行這個語句,是以profile看了也沒什麼用,和之前的資料應該是差不多的,那麼為什麼優化器不選擇走索引?

Step3 Optimizer trace

Optimizer trace是MySQL5.6添加的新功能,可以看到大量的内部查詢計劃産生的資訊,可以用如下方式打開

MySQL之SQL分析三部曲

然後在information_chema.optimizer_trace的表裡面查找這一條語句對應的資訊

MySQL之SQL分析三部曲

内容是json格式的,是以推薦找一個json的轉換工具來輔助檢視,這個json主要分為三個部分

MySQL之SQL分析三部曲

有關執行計劃的選擇,主要在第二部分裡面

MySQL之SQL分析三部曲

那麼可以看看這兩個分支的内容

MySQL之SQL分析三部曲

在這裡面能看到詳細的統計資訊,包括cost,預計的rows,以及查詢優化器最終的選擇chosen,發現在考慮排序的影響時,并沒有使用索引(index:“unknown”)

即便是加了use index,但是在Optimize trace裡面依然選擇了使用全表掃描,而使用了索引并沒有什麼優化到file sort,因為使用use index指定的index被放在了range index的考慮範圍内

因為并沒有讀源碼的計劃,是以隻能是做出推測:在有where條件的前提下,MySQL優化器并不會為order by 專門去計算一次cost,因為掃描這個索引并不會對where條件的行篩選有任何的幫助,到頭來還是隻能全表掃描,篩選出符合條件的行;如果非要用index.column,反而還要根據行标記回頭去讀取index的内容選出需要的資料,再重新來獲得有序的行标記,本末倒置了。(_(:з」∠)_看起來有理有據讓人信服的推斷)

MySQL之SQL分析三部曲
MySQL之SQL分析三部曲

那麼有什麼辦法能讓file sort利用上索引麼?

答案是:用聯合索引把where篩選條件的那些列和order by 的列全部包含進去....(對于這個例子并不推薦,因為聯合索引的列數量偏多;除非這種查詢的數量極多)

輸出資訊分為兩個部分,

MySQL之SQL分析三部曲

從這一部分可以看到,MySQL内部把=的操作全部換成了range,也計算了使用索引和全表掃描的cost,(用上了新的索引,意料之中)

下一部分可以看到最終決定的執行計劃,以及order by階段索引的使用情況

MySQL之SQL分析三部曲

--------------------------------------------------------------------------稍顯淩亂的部落格的結尾處---------------------------------------------------------------------------

總結:explain可以應對大多數的狀況;show profile可以幫我們更好的分析SQL優化的主要目标,是鎖?還是磁盤讀寫?還是檔案排序?等等...;而最後的optimize_trace則适合于各種疑難雜症了,比如說優化器為什麼沒有選擇索引而是全表掃描?為什麼優化器沒有選擇效率較好的索引,而是選擇了一個效率較差的索引(order by)?等等亂七八糟的奇怪現象.....