PostgreSQL的pg_stat_activity视图是数据库运维中最核心的诊断入口之一。它由统计收集器维护,每一个后端进程对应一行记录,数据库会持续更新其中的连接状态、事务状态、当前查询文本以及等待事件。要高效使用这个视图,首先要理解它不是历史事件表,而是一个实时快照集合;一旦会话断开,对应行就会消失。因此,排查连接数暴涨、慢查询阻塞、锁等待等问题时,可以直接从这里拿到第一手信息。

理解 pg_stat_activity 的字段与数据来源
pg_stat_activity 中的每一行都有一个 pid 列,它对应操作系统层面的后端进程 ID。通过 pid 可以直接调用诊断函数,例如 pg_cancel_backend(pid) 或 pg_terminate_backend(pid)。其他关键字段包括:datname 表示数据库名,usename 表示登录角色,client_addr 记录客户端来源地址,application_name 由应用自行设置,用于标识不同服务或模块。backend_start 表示连接建立时间,xact_start 表示当前事务开始时间,query_start 表示当前查询开始时间,这三个时间戳常用来计算连接、事务和查询的持续时长。
state 字段是判断会话是否活跃的核心。它可能的值包括 active、idle、idle in transaction 以及 idle in transaction (aborted) 等。其中 active 表示正在执行SQL;idle 表示连接空闲,没有待处理任务;idle in transaction 表示事务已开始但当前没有运行SQL,这种会话持有事务资源,可能阻塞真空回收和锁释放,是需要重点关注的类型。了解这些状态后,才能根据业务场景准确过滤。
另一个容易忽视的字段是 backend_type。client backend 表示来自客户端连接的普通会话,而 autovacuum worker、background worker、walsender 等则属于数据库后台进程。日常监控连接数时通常只关注 client backend,否则可能把自动清理进程误认为异常连接,导致错误的终止操作。
实时定位活跃查询与长事务
活跃查询是最直接的诊断对象。假设数据库突然出现CPU或IO飙高,可以先查询正在执行的SQL及其运行时长,按持续时间倒序排列。下面SQL会列出所有处于 active 状态的会话,并计算查询已经执行的时间。
SELECT pid,
usename,
datname,
application_name,
state,
now() - query_start AS query_duration,
wait_event_type,
wait_event,
query
FROM pg_stat_activity
WHERE state = 'active'
AND backend_type = 'client backend'
ORDER BY query_start;
这段语句中,now() - query_start 的结果是一个 interval,可以直接看到每个查询运行了多久。如果某个查询持续时间远超预期,再结合 wait_event_type 和 wait_event 可以判断它是在等待IO、CPU还是锁。比如 wait_event_type = 'IO' 表示可能受磁盘读写限制,wait_event_type = 'Lock' 则需要进一步排查锁等待。
不过需要注意,查询运行时间长并不等于事务运行时间长。有些查询本身很快结束,但应用没有及时提交或回滚,导致事务一直挂着,状态变为 idle in transaction。这类会话在 query_start 上可能是空的或很早,但 xact_start 非常久远。它们同样会持有事务级别的锁和快照,是很多线上隐患的根源。可以通过下面的SQL单独找出长时间未关闭的事务。
SELECT pid,
usename,
datname,
application_name,
now() - xact_start AS txn_duration,
now() - state_change AS state_duration,
query
FROM pg_stat_activity
WHERE state IN ('idle in transaction', 'idle in transaction (aborted)')
AND now() - xact_start > interval '5 minutes'
AND backend_type = 'client backend'
ORDER BY xact_start;
结果中如果出现大量 idle in transaction 且持续时间较长,通常说明应用代码在事务中执行了外部调用、网络请求或等待用户输入。解决思路包括在进入长事务前先提交、拆分事务边界,以及在数据库层设置 idle_in_transaction_session_timeout 来自动终止超时的空闲事务。
排查锁等待与阻塞会话
当多个事务同时操作同一行或同一张表时,后发会话可能进入锁等待。pg_stat_activity 的 wait_event_type 字段会标明等待类型,wait_event 会给出更细的锁名称。常见的锁等待类型是 Lock,其下可能显示 relation、transactionid、tuple 等。出现这些等待时,说明当前会话已经被其他会话阻塞。
要快速定位阻塞源头,可以使用系统函数 pg_blocking_pids。它接收一个后端进程 ID,返回阻塞该进程的所有进程 ID 列表。下面的语句将等待锁的会话与阻塞它的会话关联起来,方便直接看到阻塞链。
SELECT blocked.pid AS blocked_pid,
blocked.usename AS blocked_user,
blocked.query AS blocked_query,
blocking.pid AS blocking_pid,
blocking.usename AS blocking_user,
blocking.query AS blocking_query,
now() - blocking.xact_start AS blocking_txn_duration
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE blocked.wait_event_type = 'Lock'
AND blocked.backend_type = 'client backend'
ORDER BY blocking_txn_duration DESC;
这段SQL先筛选出正在等待锁的会话 blocked,再通过 pg_blocking_pids 找到阻塞源进程 ID,并用 ANY 与 blocking 表关联。结果中 blocking_query 可能为空,因为阻塞会话不一定是活跃查询,很可能是 idle in transaction。这种情况下虽然它没执行SQL,但事务持有锁,仍然会阻塞别人。
处理锁等待时,不能直接杀掉所有阻塞者。如果阻塞会话是长事务,直接终止会导致它整个回滚,可能影响业务。可以先尝试使用 pg_cancel_backend 取消当前查询;如果会话已经空闲但事务未结束,再用 pg_terminate_backend 终止连接。同时,在应用层设置 lock_timeout 和 deadlock_timeout 能减少长时间锁等待和死锁的影响。
清理空闲事务与连接泄漏
空闲事务是数据库常见的慢性问题。它不像锁等待那样立刻报错,但会持续占用连接、阻止表空间回收,还会让 autovacuum 无法清理过期的行版本,导致表和索引膨胀。监控时可以把重点放在 state = 'idle in transaction' 的会话上,并按应用来源分组统计。
SELECT application_name,
datname,
usename,
COUNT(*) AS session_count,
MAX(now() - xact_start) AS max_txn_age
FROM pg_stat_activity
WHERE state = 'idle in transaction'
AND backend_type = 'client backend'
GROUP BY application_name, datname, usename
ORDER BY max_txn_age DESC;
这段统计结果可以快速定位是哪个应用模块遗留了未关闭事务。如果某个 application_name 的会话数量和最大事务年龄明显异常,开发人员可以重点检查该模块的数据库访问代码。值得注意的是,连接池中的会话复用会掩盖某些事务未提交问题,因为连接不会真正断开,只是回到池中,而事务状态可能并没有结束。
对于单纯的空闲连接,即 state = 'idle',它们本身不持有事务,一般不会直接引起锁问题,但数量过多会耗尽 max_connections,导致新连接无法建立。可以通过按客户端地址或应用名分组,观察连接分布是否合理。例如某个实例节点连接数异常高,但查询状态全是 idle,可能是应用没有正确释放连接,连接池参数配置不合理,或者存在连接泄漏。
SELECT client_addr,
application_name,
COUNT(*) AS idle_connections
FROM pg_stat_activity
WHERE state = 'idle'
AND backend_type = 'client backend'
GROUP BY client_addr, application_name
ORDER BY idle_connections DESC;
如果确认是应用连接泄漏,需要从连接池空闲连接回收策略、客户端超时设置以及代码中连接关闭逻辑入手。数据库端也可以配置 idle_session_timeout 来主动断开长期空闲连接,但这会对依赖长连接的应用造成影响,启用前应充分验证。
监控脚本与注意事项
日常巡检中,可以把前面的逻辑组合成一个综合监控查询,放在 psql 的 \watch 命令中定时刷新。下面这个查询每执行一次,就能看到当前活跃会话、空闲事务和锁等待的概况,适合放在运维终端上实时观察。
SELECT pid,
usename,
datname,
application_name,
state,
wait_event_type,
wait_event,
now() - query_start AS query_age,
now() - xact_start AS txn_age,
left(query, 80) AS query_text
FROM pg_stat_activity
WHERE backend_type = 'client backend'
AND (state = 'active'
OR state IN ('idle in transaction', 'idle in transaction (aborted)')
OR wait_event_type = 'Lock')
ORDER BY query_start NULLS LAST;
在 psql 中执行 \watch 5 可以每5秒重新运行一次上一条SQL,形成实时监控效果。如果需要把这些信息接入外部监控系统,可以基于 pg_stat_activity 编写采集脚本,定期插入到时序数据库或告警平台。关注点除了连接数,还应包括长事务数量、锁等待数量和最大事务年龄等指标。
使用 pg_stat_activity 时有几个权限和显示上的限制需要注意。普通数据库用户只能看到与自己相关的会话,要查看所有会话需要 pg_read_all_stats 角色或超级用户权限。此外,query 字段的长度由 track_activity_query_size 决定,默认值为 1024 字节,超过部分会被截断;如果权限不足,查询内容可能显示为空或提示权限不足。在监控复杂SQL时,可以适当调大该参数,或配合 pg_stat_statements 扩展查看完整的SQL指纹。
另外一个容易忽略的点是 backend_type 过滤。虽然大多数连接问题来自 client backend,但某些后台进程也可能引发资源占用,例如 autovacuum worker 可能执行大型表清理,导致IO升高;walsender 可能因为备库传输压力而占用网络和CPU。遇到系统整体负载异常时,可以去掉 backend_type 过滤条件,观察所有后端进程状态。无论如何,终止进程前一定要确认进程类型,避免误杀数据库自身的维护任务。
pg_stat_activityPostgreSQL会话监控实时会话查询修改时间:2026-10-05 18:20:49