如何杀掉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也不知道,所以迫不得已再使用。

好吧,加油吧。