MySQL一次慢查詢導致的故障

cg4f 9年前發布 | 12K 次閱讀 MySQL 數據庫服務器

一 引子

很久沒寫技術文章了,打算最近幾周把最近遇到的故障總結下。這篇文章分享周四遇到的故障。

另外,最近有創作欲望,只等時間寬裕。

二 起因

周四一整天,研發反應某臺數據庫僵死,后面的會話要么連接不上,要么要花費大量的時間返回結果,哪怕是一個簡單的查詢。

三 處理

首先去監控平臺查看服務器以及數據庫狀態,發現這臺數據庫有大量的慢查詢。繼續看服務器監控,CPU 平均使用率較高,IO 讀寫平均值正常。登錄到 MySQL,使用 SHOW PROCESSLIST 查看會話狀態,總數居然有 600+,這是很不正常的。查看慢查詢日志,發現出問題的 SQL 主要集中在幾個,有 SUM、有 COUNT、有等值操作等等。這臺 MySQL 服務器的 long_query_time 設置為 3秒,而一個簡單的查詢卻要幾十秒,這顯然是有問題的。寫腳本試著 kill 掉相關的會話,發現于事無補,仍然有大量的連接進來。此時使用 top 查看服務器狀態,mysqld 進程占用內存和 CPU 居高不下。

故障期間的慢查詢數,如圖:

MySQL一次慢查詢導致的故障

CPU 平均使用率,如圖:

MySQL一次慢查詢導致的故障

接著使用 SHOW FULL PROCESSLIST 查看完整狀態,在最上面居然發現幾條 SQL。這些 SQL 操作使用子查詢實現,TIME 列居然達到了 30000 秒,折算過來差不多 10 小時。EXPLAIN 這些語句,居然出現了 USING TEMPORY 和 USING FILESORT,可以看出這些語句是很糟糕的。于是跟開發確認,緊急把這些會話 kill 掉。稍等片刻,會話數立馬降下來,只有 100+,top 查看 mysqld 進程,內存和 CPU 都呈現下降的趨勢。接著分析開發說上午 9 時寫了這些 SQL,發現有問題,注釋掉了。新的代碼雖然沒有此類 SQL,但之前建立的連接并不會釋放。解決問題和出現問題的時間差剛好可以和添加子查詢的時間對應,就可以確認子查詢是此次故障的罪魁禍首。

四 總結

通過這個故障,總結如下幾點:

  • MySQL 應該盡量避免使用子查詢,即使使用,也要搞清楚大表和小表的關系;
  • 出現這類問題的排查步驟:

    1. 第一,查看服務器監控和 MySQL 監控,分析服務器以及 MySQL 性能,找出異常;
    2. 第二,如果是慢查詢導致,查看慢查詢日志,找出出現問題的 SQL,試著優化,或者把結果緩存;
    3. 第三,分清主次,先解決大塊問題,后解決細小問題。 把大塊的異常解決,小問題就迎刃而解了。比如本文中的例子,把耗費時間長的會話 kill 掉后,后面的連接就正常了;
    4. 第四,總結分析。
    5. </ol> </li>

    6. 高效的溝通會事半功倍;
    7. DBA 需要定期給出 Top N SQL(類 Oracle 的說法),提供給開發,并協助優化;
    8. 查看監控時,不管是服務器監控還是 MySQL 監控,需要做對比,比如和昨天甚至前天的同一時間對比,這會更加快速地定位問題。
    9. </ul>

      五 技巧

      最后,附上一個快速 kill 掉 MySQL 會話的方法:

      首先使用如下語句分析出有問題的 SQL:

      /usr/local/mysql/bin/mysql -uroot -p'XXX' \ -e "SHOW FULL PROCESSLIST;" | more

      然后將 SHOW FULL PROCESSLIST 的結果保存到一個文件:

      /usr/local/mysql/bin/mysql -uroot -p'XXX' \
      -e "SHOW FULL PROCESSLIST;" | \
      grep "XXX" | awk '{print $1}' > mysql_slow.txt

      最后使用如下簡單的 Shell 腳本 kill 掉相關會話:

      #!/bin/bash

      Author: Robin Wen

      Date: 2015-07-09 18:37:29

      Desc: Kill slow query session.

      for i in cat mysql_slow.txt do /usr/local/mysql/bin/mysql -uroot -p'XXX' -e "kill $i" done</pre>

      當然也可以使用如下 SQL 拼接 kill 語句:

      SELECT concat('kill ',id,';')
      FROM information_schema.processlist
      WHERE info like 'XXX';

      原文 http://dbarobin.com/2015/07/12/mysql-slow-query/

 本文由用戶 cg4f 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!