这是本节的多页打印视图。
.
返回本页常规视图.
Lock 等待
通常可以直接从 SQL 找到持有者与阻塞链的重量级锁。
Lock 是最容易直接处置的一类:后端向锁管理器申请重量级锁,但不兼容的持有者尚未释放。与 LWLock 不同,这些等待通常在 pg_locks 中有对应行,pg_blocking_pids() 也能给出有效答案。
看阻塞图,不要只数受害者
二十个等待者可能都只是一个空闲事务的症状。先走到阻塞图最前端,再判断持有者是在做有效工作、已被遗弃,还是处于计划内 DDL/发布窗口。
- 正常: 普通写入或计划内 DDL 期间,亚秒级的锁交接。
- 关注: 任一面向用户的等待超过其延迟目标,或至少 10% 的活动会话等待同一个根阻塞者。
- 紧急: 根持有者是
idle in transaction、阻塞链持续增长、关键 DDL 阻塞流量,或死锁开始增加。
值得先认出的事件
阻塞者查询
SELECT w.pid AS waiting_pid, b.pid AS blocking_pid,
w.wait_event, now() - w.query_start AS waiting_for,
now() - b.xact_start AS blocker_xact_age,
b.state AS blocker_state,
left(w.query, 100) AS waiting_query,
left(b.query, 100) AS blocking_query
FROM pg_stat_activity AS w
CROSS JOIN LATERAL unnest(pg_blocking_pids(w.pid)) AS x(pid)
JOIN pg_stat_activity AS b ON b.pid = x.pid
ORDER BY waiting_for DESC;
常见误读
- 被列为阻塞者的会话并不一定可以安全终止;它可能是维护业务不变量的唯一写入者。
transactionid 不代表事务 ID 即将耗尽。
relation 本身不说明具体关系;需要把 pg_locks.relation 关联到 pg_class。
- 增大
lock_timeout 只改变受害者等多久,并不会移除阻塞者。
1 - Lock: advisory
等待获取用户 advisory lock。
PostgreSQL 等待事件档案
类别Lock
事件advisory
版本PG 13-18
证据3 个源码位置
官方描述译文
等待获取用户 advisory lock。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:428。探针覆盖的操作是:等待获取用户 advisory lock。锁管理器无法立即授予 advisory 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'advisory'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'advisory'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
2 - Lock: applytransaction
等待获取逻辑复制订阅端正在应用的远程事务上的锁。
PostgreSQL 等待事件档案
类别Lock
事件applytransaction
版本PG 16-18
证据3 个源码位置
官方描述译文
等待获取逻辑复制订阅端正在应用的远程事务上的锁。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:429。探针覆盖的操作是:等待获取逻辑复制订阅端正在应用的远程事务上的锁。锁管理器无法立即授予 applytransaction 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'applytransaction'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'applytransaction'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
3 - Lock: extend
等待扩展 relation。
PostgreSQL 等待事件档案
类别Lock
事件extend
版本PG 13-18
证据3 个源码位置
官方描述译文
等待扩展 relation。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:419。探针覆盖的操作是:等待扩展 relation。锁管理器无法立即授予 extend 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'extend'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'extend'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
4 - Lock: frozenid
等待更新 pg_database.datfrozenxid 和 pg_database.datminmxid。
PostgreSQL 等待事件档案
类别Lock
事件frozenid
版本PG 13-18
证据3 个源码位置
官方描述译文
等待更新 pg_database.datfrozenxid 和 pg_database.datminmxid。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:420。探针覆盖的操作是:等待更新 pg_database.datfrozenxid 和 pg_database.datminmxid。锁管理器无法立即授予 frozenid 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'frozenid'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'frozenid'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
5 - Lock: object
等待获取非 relation 数据库对象上的锁。
PostgreSQL 等待事件档案
类别Lock
事件object
版本PG 13-18
证据3 个源码位置
官方描述译文
等待获取非 relation 数据库对象上的锁。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:426。探针覆盖的操作是:等待获取非 relation 数据库对象上的锁。锁管理器无法立即授予 object 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'object'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'object'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
6 - Lock: page
等待获取 relation 页面上的锁。
PostgreSQL 等待事件档案
类别Lock
事件page
版本PG 13-18
证据2 个源码位置
官方描述译文
等待获取 relation 页面上的锁。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:421。探针覆盖的操作是:等待获取 relation 页面上的锁。锁管理器无法立即授予 page 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'page'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'page'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
7 - Lock: relation
等待获取 relation 上的锁。
PostgreSQL 等待事件档案
类别Lock
事件relation
版本PG 13-18
证据3 个源码位置
官方描述译文
等待获取 relation 上的锁。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:418。探针覆盖的操作是:等待获取 relation 上的锁。锁管理器无法立即授予 relation 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'relation'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'relation'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
8 - Lock: spectoken
等待获取推测式插入锁。
PostgreSQL 等待事件档案
类别Lock
事件spectoken
版本PG 13-18
证据3 个源码位置
官方描述译文
等待获取推测式插入锁。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:425。探针覆盖的操作是:等待获取推测式插入锁。锁管理器无法立即授予 spectoken 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'spectoken'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'spectoken'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
9 - Lock: transactionid
等待事务结束。
PostgreSQL 等待事件档案
类别Lock
事件transactionid
版本PG 13-18
证据3 个源码位置
官方描述译文
等待事务结束。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:423。探针覆盖的操作是:等待事务结束。锁管理器无法立即授予 transactionid 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'transactionid'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'transactionid'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
10 - Lock: tuple
等待获取 tuple 上的锁。
PostgreSQL 等待事件档案
类别Lock
事件tuple
版本PG 13-18
证据3 个源码位置
官方描述译文
等待获取 tuple 上的锁。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:422。探针覆盖的操作是:等待获取 tuple 上的锁。锁管理器无法立即授予 tuple 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'tuple'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'tuple'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
11 - Lock: userlock
等待获取用户锁。
PostgreSQL 等待事件档案
类别Lock
事件userlock
版本PG 13-18
证据3 个源码位置
官方描述译文
等待获取用户锁。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:427。探针覆盖的操作是:等待获取用户锁。锁管理器无法立即授予 userlock 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'userlock'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'userlock'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据
12 - Lock: virtualxid
等待获取虚拟事务 ID 锁。
PostgreSQL 等待事件档案
类别Lock
事件virtualxid
版本PG 13-18
证据3 个源码位置
官方描述译文
等待获取虚拟事务 ID 锁。
触发机制
PG_WAIT_LOCK 位于 src/backend/storage/lmgr/proc.c:1487,是经 grep 核验的报告路径。公共身份/资源映射位于 src/backend/utils/activity/wait_event_names.txt:424。探针覆盖的操作是:等待获取虚拟事务 ID 锁。锁管理器无法立即授予 virtualxid 重量级锁;ProcSleep 报告等待,并把后端挂到该锁的等待队列,直到持有者释放或请求被取消。
正常还是麻烦?
- 正常: 普通写入或计划内 DDL 的亚秒级锁交接可能正常。
- 需要调查: 面向用户的等待超过延迟目标、阻塞链持续增长,或根持有者处于 idle in transaction 时,应当调查。
诊断 SQL
SELECT pid, backend_type, usename, datname, application_name,
state, now() - query_start AS query_age,
now() - xact_start AS xact_age,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS blocking_pids,
left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
AND wait_event = 'virtualxid'
ORDER BY query_age DESC NULLS LAST;
SELECT wait_event, count(*) AS waiting_sessions,
count(*) FILTER (WHERE state = 'active') AS active_waiters,
max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
d.datname, n.nspname, c.relname,
l.page, l.tuple, l.virtualxid, l.transactionid,
l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
ON c.oid = l.relation
AND l.database = (
SELECT oid FROM pg_database WHERE datname = current_database()
)
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Lock'
AND a.wait_event = 'virtualxid'
ORDER BY a.pid, l.granted, l.locktype, l.mode;
处置建议
- 沿 pg_blocking_pids 构建到根节点的阻塞图。
- 检查根持有者状态、事务年龄与业务目的。
- 确认最安全的根动作后,再选择取消、超时或调整负载顺序。
源码证据