如何殺掉pg資料庫正在運行的sql
- 2019 年 12 月 18 日
- 筆記
我們在生產環境可能經常遇到長sql,長sql對資料庫的影響還是挺大的,不僅可能對主機資源消耗較大,還可能會阻塞其他sql的正常執行,所以對於長sql我們要尤其注意。一般生產環境都會配置長sql告警,可以根據業務情況調整告警閾值。
那麼在postgresql資料庫如果遇到了長sql告警我們應該怎麼處理呢?我總結一下:一查二看三殺。
一查:
首先我們要定位到是哪條sql引起的告警。登錄pg資料庫查看pg_stat_activity(pgxc架構使用pgxc_stat_activity)視圖,通過query_start欄位查看sql的開始運行時間,state欄位表明了當前sql的狀態,一般有三種:active表示sql活躍正在執行;idle表示當前該連接空閑,上一條sql已經執行完畢,當前沒有sql在執行;idle in transaction表示當前事務還未結束,事務中上一條sql已經執行完畢,當前事務沒有sql在執行,事務中空閑。pg_stat_activity視圖中還有個pid欄位,這個欄位是當前連接的進程/執行緒號,這個我們後面處理的依據。
二看:
二看執行計劃,我們使用explain 命令查看當前sql的執行計劃,確認sql執行計劃是否正確,是否走到了索引,是否走到了正確的索引,如果沒有走正確索引,我們可以對錶進行分析,重新收集統計資訊。如果想得到更精確的資訊,可以使用explain performance命令來查看更詳細的執行計劃資訊,值得注意的是explain不會真正執行sql,而explain performance會真正執行sql。
三殺:
在定位sql後,我們往往會跟業務確認這條sql是否能夠殺掉,當業務確認後,我們就需要殺掉該sql。
pg資料庫殺掉某條sql有三種方法,也可以稱為三板斧:cancel->terminate->kill
①使用pg_cancel_backend(pid)殺掉某條sql,這個是溫柔的殺,向後台發送sigint訊號,關閉當前後台進程,用戶只能關閉自己的後台進程,事務回滾。
②使用pg_terminate_backend(pid)殺掉某條sql,這個是強殺,向後台發送sigterm訊號,關閉當前後台進程,需要有超級用戶許可權,超級用戶可以關閉所有後台進程,事務回滾。
③這裡為什麼會有第三種殺法呢?可能大家遇到過,使用pg_cancel_backend殺不掉的進程,但是其實pg_terminate_backend有時也無法殺掉某條sql,筆者在生產環境遇到過,這時我們可能會抓一下該連接的堆棧,然後我們可能想儘快殺掉該sql,問題原因後面再分析,這時我們就要從作業系統層面使用kill命令來殺掉連接了。通過上面查到的pid,在作業系統上ps -ef |grep pid查看當前連接的狀態,然後kill -9 pid殺掉該連接。
postgres=# select pid,query_start,state,query from pg_stat_activity where state='active'; pid | query_start | state | query -------+-------------------------------+--------+-------------------------------------------------------------------------------- 5001 | 2019-08-13 12:45:16.652909+08 | active | select * from perf_analyse; 18876 | 2019-08-13 12:45:19.019691+08 | active | select pid,query_start,state,query from pg_stat_activity where state='active'; (2 rows) postgres=# q postgres@xxx:~> ps -ef |grep 5001 postgres 5001 23550 64 12:45 ? 00:00:13 postgres: postgres postgres [local] SELECT postgres 7677 6228 0 12:45 pts/3 00:00:00 grep --color=auto 5001 postgres@xxx:~> kill -9 5001
上面三板斧在生產環境中還是建議從前到後執行,雖然第三種方法最直接有效,但是畢竟是生產環境,萬一觸發什麼bug也不知道,所以迫不得已再使用。
好吧,加油吧。