SQL調優 - Hints指定索引 解決慢查詢案例

背景

    每當交易高峯時期,可能會暴露一些平時沒法發現的問題,機遇和挑戰並存。下面聊聊最近解決的一個案例,由於執行計劃走錯致使慢查詢,進而引起應用線程阻塞、線程池爆滿,最後應用功能癱瘓。如何標本兼治的解決問題,須要不少思考。sql

問題分析

   step1 應用癱瘓

    用戶反應某查詢功能一直處於加載中,並出現錯誤提示。查看後臺應用日誌,調用遠程查詢服務出現大量超時。數據庫

   step2 線程池爆滿

    經過jstack命令來分析查詢服務jvm線程堆棧,發現設定的線程池已經滿了,並且大部分線程阻塞在了數據庫查詢階段(以下圖),看來是有不少慢查詢。oracle

 

step3 慢查詢的由來 - 錯誤執行計劃

爲什麼突然出現這麼多慢查詢?咱們來分析一下:jvm

 

  1. SELECT no, time
  2. FROM tablename
  3. where no = :1
  4. and time >= to_date(:2, 'yyyy-mm-dd')
  5. and time < to_date(:3, 'yyyy-mm-dd')
  6. ORDER BY time DESC

注:條件字段(no、time)分別有索引(idx_no、idx_time)。性能

通過DBA幫助,分析上段sql的執行計劃發現:優化

  • 有時數據庫會走idx_no索引,查詢很快spa

 

  • 有時會走idx_time索引,查詢很慢線程

 

 

解決方案

    既然數據庫自動生成的執行計劃有時會出問題,那麼咱們能夠用hints語句指定當前sql走哪條索引,以固定執行計劃。日誌

下面以Oracle爲例,添加hints:code

  1. SELECT /*+ index(tablename IDX_NO) */ no, time
  2. FROM tablename
  3. where no = :1
  4. and time >= to_date(:2, 'yyyy-mm-dd')
  5. and time < to_date(:3, 'yyyy-mm-dd')
  6. ORDER BY time DESC

若是感受在sql中添加不方便的話,oracle 10g以上版本提供了SQL Profile方式。

 

總結思考

    這個問題應該一直有,爲什麼在交易高峯時段才表現出來值得去研究。

    數據庫:平時數據庫壓力較小,出現幾個走錯執行計劃的慢查詢,也只是讓數據庫壓力比均值高出一小部分,性能未受影響。可是,高峯時段數據庫自己就處於一個高負載狀態,這時出現的慢查詢無疑是雪上加霜,接近某個臨界點時性能就明顯下滑。

    應用:慢查詢會致使線程阻塞等待,一直佔用線程池資源。咱們知道,用戶在點擊查詢按鈕後發現一直加載,會不知覺多點幾遍。這樣的話,線程數量暴漲且大部分處於阻塞狀態,線程池滿了以後應用就會癱瘓掉,使其餘正常的接口也沒法正常工做。

    綜上所述,數據層的優化是治本,同時還要藉助一些手段來保證不出現雪崩式性能降低。好比,在前臺頁面添加劇復提交限制,儘可能避免短期內產生大量慢查詢。

參考資料

Oracle Hints:https://docs.oracle.com/cd/B12037_01/server.101/b10752/hintsref.htm#5156

Oracle SQL Profile:https://docs.oracle.com/database/121/TGSQL/tgsql_profiles.htm#TGSQL596

相關文章
相關標籤/搜索