pg_cancel_backendpg_terminate_backend 函数

当你从 pg_stat_activity 确认了一个慢查询的时候,你可以获取这个慢查询所在的 pid。然后,你就可以使用 pg_cancel_backend 或者 pg_terminate_backend来终止这个慢查询。这两个函数的使用方法如下:

mydb=# select pg_cancel_backend(40955);
 pg_cancel_backend
-------------------
 t
 (1 row)
mydb=# select pg_terminate_backend(2237);
 pg_terminate_backend
----------------------
 t
 (1 row)

这两个函数的参数都是 pid,返回值是 true 或者 false,表示向进程发送信号是否成功。

这两个函数的区别如下:pg_cancel_backend 是终止当前这次的查询,连接依旧被保持,其发送的是 SIGINT 信号。pg_terminate_backend会终止连接,其发送的是 SIGTERM 信号。

示例

我们可以构造一个例子来看一下他们的区别。这个例子需要启用三个 psql,分别命名为 A, B, Manage

psql A 中执行如下语句,启动一个事务,然后锁住一些行:

mydb=# begin;
BEGIN
mydb=# select * from host where id=1 for update;
 id |               uuid               |  name   |   admin_ip   | status
----+----------------------------------+---------+--------------+--------
  1 | 26197b2829544da5a54d23d5b7622eaa | node204 | 10.252.3.204 | active
(1 row)

此时,因为还没有提交事务,所以 psql A 锁住了这一行。

psql B 执行如下语句:

mydb=# select * from host where id=1 for update;

然后该查询就会挂起等待。

可以通过 psql Manage 来查询:

mydb=# select datname, pid, usename, wait_event_type, wait_event, state, query from pg_stat_activity where usename='postgres';
 datname |  pid  | usename  | wait_event_type |  wait_event   |        state        |                          query
---------+-------+----------+-----------------+---------------+---------------------+----------------------------------------------------------
 mydb    | 37159 | postgres | Lock            | transactionid | active              | select * from host where id=1 for update;
 mydb    | 36520 | postgres |                 |               | idle in transaction | select * from host where id=1 for update;
 mydb    | 37564 | postgres |                 |               | active              | select * from pg_stat_activity where usename='postgres';
(3 rows)

其中 pid37159 的连接所执行的查询,正在等待锁。这个时候我们就可以用 pg_cancel_backend 来取消这次查询:

mydb=# select pg_cancel_backend(37159);
 pg_cancel_backend
-------------------
 t
(1 row)

此时,在 psql B中,可以看到:

mydb=# select * from host where id=1 for update;
ERROR:  canceling statement due to user request
CONTEXT:  while locking tuple (0,7) in relation "host"

此时,在 psql Manage 中查看 pg_stat_activity 可以看到 psql B 的连接还在,pid 不变,但是连接已经处于 idle 状态:

mydb=# select datname, pid, usename, wait_event_type, wait_event, state, query from pg_stat_activity where usename='postgres';
 datname |  pid  | usename  | wait_event_type | wait_event |        state        |                                                        query
---------+-------+----------+-----------------+------------+---------------------+-------------------------------------------------------------------------------------------------------------------------
 mydb    | 37159 | postgres |                 |            | idle                | select * from host where id=1 for update;
 mydb    | 36520 | postgres |                 |            | idle in transaction | select * from host where id=1 for update;
 mydb    | 37564 | postgres |                 |            | active              | select datname, pid, usename, wait_event_type, wait_event, state, query from pg_stat_activity where usename='postgres';
(3 rows)

接下来来测试另外一个函数,同样在 psql B 中执行如下语句来触发挂起:

mydb=# select * from host where id=1 for update;

然后,在 psql Manage 中执行:

mydb=# select pg_terminate_backend(37159);
 pg_terminate_backend
----------------------
 t
(1 row)

psql B 中可以看到:

mydb=# select * from host where id=1 for update;
FATAL:  terminating connection due to administrator command
CONTEXT:  while locking tuple (0,7) in relation "host"
server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
The connection to the server was lost. Attempting reset: Succeeded.

表明,连接已经断开了。此时,再次查看 pg_stat_activity 可以发现 pid 已经变了,变成了 39248

mydb=# select datname, pid, usename, wait_event_type, wait_event, state, query from pg_stat_activity where usename='postgres';
 datname |  pid  | usename  | wait_event_type | wait_event |        state        |                                                          query
---------+-------+----------+-----------------+------------+---------------------+-------------------------------------------------------------------------------------------------------------------------
 mydb    | 39248 | postgres |                 |            | idle                |
 mydb    | 36520 | postgres |                 |            | idle in transaction | select * from host where id=1 for update;
 mydb    | 37564 | postgres |                 |            | active              | select datname, pid, usename, wait_event_type, wait_event, state, query from pg_stat_activity where usename='postgres';
(3 rows)

知识共享许可协议本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。