背景
被阻塞的 SQL 不一定是罪魁祸首,真正的阻塞者可能已经 idle in transaction。排障要先还原阻塞链和事务年龄。
核心判断
- 用 pg_blocking_pids 获取阻塞者,再关联 pg_stat_activity。
- 同时观察 wait_event、xact_start 和应用名,判断锁等待来源。
- 先与业务方确认事务副作用,再决定取消语句或终止会话。
最小示例
下面保留核心逻辑;业务类型、调用入口和环境配置按项目补齐。
SELECT blocked.pid AS blocked_pid,
blocker.pid AS blocking_pid,
now() - blocker.xact_start AS blocking_xact_age,
blocked.wait_event_type,
blocked.wait_event,
blocked.query AS blocked_query,
blocker.query AS blocking_query
FROM pg_stat_activity AS blocked
CROSS JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS p(pid)
JOIN pg_stat_activity AS blocker ON blocker.pid = p.pid
ORDER BY blocking_xact_age DESC NULLS LAST;
边界与误区
仅按 locktype 连接 pg_locks 会错误关联不同锁对象。示例使用官方阻塞关系函数;高频查询也有开销,诊断权限与采样频率应受控。
验证方式
建立一个长事务持锁,再让第二个连接等待,核对阻塞 PID 与 SQL。确认取消当前语句和结束整个会话的风险不同,不自动执行终止命令。
小结
监控阻塞者、被阻塞者、事务年龄和 SQL,区分长事务、DDL 与业务冲突。