1. PostgreSQL阻塞分析利器:pg_blocking_pids()函数解析
当数据库查询突然陷入停滞,应用日志里堆满超时错误时,有经验的DBA第一个反应就是——查阻塞。PostgreSQL提供的pg_blocking_pids()函数就像数据库里的CT扫描仪,能精准定位造成阻塞的罪魁祸首。这个看似简单的函数背后,藏着PG多版本并发控制(MVCC)的实现精髓。
上周我们生产环境就遭遇了一次诡异的死锁:凌晨批量作业卡死,连带拖垮了整个应用的响应速度。正是用这个函数配合pg_stat_activity,五分钟内就揪出了那个忘记提交事务的Python脚本。下面我就结合这次实战,详细拆解这个救命函数的使用技巧。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 函数工作原理与核心参数
2.1 函数签名与返回值
sql复制pg_blocking_pids(integer) → integer[]
这个函数的输入参数是待检查的会话PID,返回的是一个整数数组,包含所有阻塞该会话的其他会话PID。如果返回空数组,说明当前会话没有被阻塞。
关键点在于:阻塞是层级式的。A阻塞B,B阻塞C,那么查询C的阻塞情况时会返回B,而不会直接返回A。需要递归查询才能找到阻塞链的源头。
2.2 底层实现机制
函数通过查询PG内部的锁管理器实现,主要涉及这些系统表:
pg_locks:当前所有锁的状态pg_stat_activity:会话活动信息pg_database:数据库信息
其工作流程是:
- 检查目标会话是否在等待锁
- 找出持有该锁且与目标会话冲突的其他会话
- 返回这些会话的PID列表
注意:函数只显示直接阻塞者,不展示完整的阻塞链。实际排查时需要配合递归查询。
3. 实战排查步骤详解
3.1 基础查询模板
sql复制SELECT
blocked_locks.pid AS blocked_pid,
blocking_locks.pid AS blocking_pid,
blocked_activity.usename AS blocked_user,
blocking_activity.usename AS blocking_user,
blocked_activity.query AS blocked_query,
blocking_activity.query AS blocking_query
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalo
