每當交易高峯時期,可能會暴露一些平時沒法發現的問題,機遇和挑戰並存。下面聊聊最近解決的一個案例,由於執行計劃走錯致使慢查詢,進而引起應用線程阻塞、線程池爆滿,最後應用功能癱瘓。如何標本兼治的解決問題,須要不少思考。sql
用戶反應某查詢功能一直處於加載中,並出現錯誤提示。查看後臺應用日誌,調用遠程查詢服務出現大量超時。數據庫
經過jstack命令來分析查詢服務jvm線程堆棧,發現設定的線程池已經滿了,並且大部分線程阻塞在了數據庫查詢階段(以下圖),看來是有不少慢查詢。oracle
爲什麼突然出現這麼多慢查詢?咱們來分析一下:jvm
SELECT no, time
FROM tablename
where no = :1
and time >= to_date(:2, 'yyyy-mm-dd')
and time < to_date(:3, 'yyyy-mm-dd')
ORDER BY time DESC
注:條件字段(no、time)分別有索引(idx_no、idx_time)。性能
通過DBA幫助,分析上段sql的執行計劃發現:優化
有時數據庫會走idx_no索引,查詢很快spa
有時會走idx_time索引,查詢很慢線程
既然數據庫自動生成的執行計劃有時會出問題,那麼咱們能夠用hints語句指定當前sql走哪條索引,以固定執行計劃。日誌
下面以Oracle爲例,添加hints:code
SELECT /*+ index(tablename IDX_NO) */ no, time
FROM tablename
where no = :1
and time >= to_date(:2, 'yyyy-mm-dd')
and time < to_date(:3, 'yyyy-mm-dd')
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