跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

Lock 等待

通常可以直接从 SQL 找到持有者与阻塞链的重量级锁。

Lock 是最容易直接处置的一类:后端向锁管理器申请重量级锁,但不兼容的持有者尚未释放。与 LWLock 不同,这些等待通常在 pg_locks 中有对应行,pg_blocking_pids() 也能给出有效答案。

看阻塞图,不要只数受害者

二十个等待者可能都只是一个空闲事务的症状。先走到阻塞图最前端,再判断持有者是在做有效工作、已被遗弃,还是处于计划内 DDL/发布窗口。

  • 正常: 普通写入或计划内 DDL 期间,亚秒级的锁交接。
  • 关注: 任一面向用户的等待超过其延迟目标,或至少 10% 的活动会话等待同一个根阻塞者。
  • 紧急: 根持有者是 idle in transaction、阻塞链持续增长、关键 DDL 阻塞流量,或死锁开始增加。

值得先认出的事件

事件 通常表示
relation 表/索引级锁冲突,常见于 DDL 对 DML
transactionid 等待另一事务结束,常见于并发更新同一行
tuple 元组锁竞争或很长的行锁队列
extend 多个会话在扩展同一关系时串行化
virtualxid DDL 等待可能仍在使用对象的事务
advisory 应用自定义的 advisory lock 协调

阻塞者查询

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 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/advisory 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

2 - Lock: applytransaction

等待获取逻辑复制订阅端正在应用的远程事务上的锁。
PostgreSQL 等待事件档案
类别Lock 事件applytransaction 版本PG 16-18 证据3 个源码位置

官方描述译文

等待获取逻辑复制订阅端正在应用的远程事务上的锁。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/applytransaction 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

3 - Lock: extend

等待扩展 relation。
PostgreSQL 等待事件档案
类别Lock 事件extend 版本PG 13-18 证据3 个源码位置

官方描述译文

等待扩展 relation。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/extend 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

4 - Lock: frozenid

等待更新 pg_database.datfrozenxid 和 pg_database.datminmxid。
PostgreSQL 等待事件档案
类别Lock 事件frozenid 版本PG 13-18 证据3 个源码位置

官方描述译文

等待更新 pg_database.datfrozenxid 和 pg_database.datminmxid。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/frozenid 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

5 - Lock: object

等待获取非 relation 数据库对象上的锁。
PostgreSQL 等待事件档案
类别Lock 事件object 版本PG 13-18 证据3 个源码位置

官方描述译文

等待获取非 relation 数据库对象上的锁。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/object 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

6 - Lock: page

等待获取 relation 页面上的锁。
PostgreSQL 等待事件档案
类别Lock 事件page 版本PG 13-18 证据2 个源码位置

官方描述译文

等待获取 relation 页面上的锁。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/page 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

7 - Lock: relation

等待获取 relation 上的锁。
PostgreSQL 等待事件档案
类别Lock 事件relation 版本PG 13-18 证据3 个源码位置

官方描述译文

等待获取 relation 上的锁。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/relation 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

8 - Lock: spectoken

等待获取推测式插入锁。
PostgreSQL 等待事件档案
类别Lock 事件spectoken 版本PG 13-18 证据3 个源码位置

官方描述译文

等待获取推测式插入锁。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/spectoken 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

9 - Lock: transactionid

等待事务结束。
PostgreSQL 等待事件档案
类别Lock 事件transactionid 版本PG 13-18 证据3 个源码位置

官方描述译文

等待事务结束。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/transactionid 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

10 - Lock: tuple

等待获取 tuple 上的锁。
PostgreSQL 等待事件档案
类别Lock 事件tuple 版本PG 13-18 证据3 个源码位置

官方描述译文

等待获取 tuple 上的锁。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/tuple 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

11 - Lock: userlock

等待获取用户锁。
PostgreSQL 等待事件档案
类别Lock 事件userlock 版本PG 13-18 证据3 个源码位置

官方描述译文

等待获取用户锁。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/userlock 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据

12 - Lock: virtualxid

等待获取虚拟事务 ID 锁。
PostgreSQL 等待事件档案
类别Lock 事件virtualxid 版本PG 13-18 证据3 个源码位置

官方描述译文

等待获取虚拟事务 ID 锁。

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

触发机制

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

正在等待 Lock/virtualxid 的会话
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;
当前 Lock 等待分布
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;

处置建议

  1. 沿 pg_blocking_pids 构建到根节点的阻塞图。
  2. 检查根持有者状态、事务年龄与业务目的。
  3. 确认最安全的根动作后,再选择取消、超时或调整负载顺序。

源码证据