天天看點

故障案例 | 一次慢SQL優化分析全過程

客戶發給我一個SQL,讓我看看,為什麼執行幾分鐘沒有執行完。

我第一眼看到SQL的時候,我也覺得很簡單,優化過程也比較簡單,但是帶來的分析過程與經驗還是值得分享的。

SQL語句如下:

update ap_receive_benefits_log
  set orderstate= i_orderstate where
  requestid = i_orderid;      

但是這個SQL執行時被嚴重阻塞了

故障案例 | 一次慢SQL優化分析全過程

該SQL的執行計劃

故障案例 | 一次慢SQL優化分析全過程

疑問1

發現執行計劃key走的主鍵,但是細看行數,會發現是全表掃描了資料。

如果沒有可用索引的情況下,執行計劃為什麼顯示走的主鍵,而不是空的呢?

疑問2

這個SQL裡的 ​

​i_orderid​

​ 字段會不會是表中的一個字段呢,如果不是字段,是哪裡來的?

分析解決步驟如下

  1. 确認表中的資料量約75萬,這個UPDATE語句每天都需要執行很多次。
  2. 檢視表後,發現并沒有 ​

    ​i_orderid​

    ​ 字段,很是奇怪。就想這個SQL怎麼來的,讓開發确認一下這個SQL的來源,我來确認執行計劃。如果是mysql 5.6以上版本可以直接檢視UPDATE的執行計劃,發現這個語句沒有利用任何索引。
  3. 開發找了半天,确認程式沒有這個語句。怎麼辦,好像成了‘沒人認領的死屍’,開發确認不了,隻能自己查了。
  4. 使用 ​

    ​pt-query-digest​

    ​ 分析最近幾個小時的慢查詢,發現問題如下:
故障案例 | 一次慢SQL優化分析全過程
  1. 有一個存儲過程執行次數很多,響應時間也是也是最大,分析此過程,檢視該存儲過程:
故障案例 | 一次慢SQL優化分析全過程
  1. 此存儲過程執行情況:
故障案例 | 一次慢SQL優化分析全過程
  1. 到此,通過檢視存儲過程,可以确認發生阻塞的語句是過程裡調用的,把存儲過程發給開發,再次得到确認。
  2. 知道語句了,優化就簡單了,先确認字段的基數(唯一性)。
故障案例 | 一次慢SQL優化分析全過程
  1. 加上索引 ​

    ​alter table ap_receive_benefits_log idx_requestId(requestId);​

    ​ 後,這個UPDATE就可以走索引了,問題解決。

再次回應上面的疑問

疑問1

為什麼update執行計劃沒有索引情況下,使用的主鍵?

這個因為update語句檢視執行計劃的時候顯示用的是主鍵,全表更新就是聚集索引,把這個update語句換成select,執行計劃就是key顯示的空。以下是測試的例子:

update的時候執行計劃

故障案例 | 一次慢SQL優化分析全過程

轉成select語句執行計劃

故障案例 | 一次慢SQL優化分析全過程

疑問2

為什麼show processlist顯示的是字段或者是變量名,誤導了我的思路?

測試一下:

建立過程并調用,延遲結果

故障案例 | 一次慢SQL優化分析全過程