# Lock 等待

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

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

## 看阻塞图，不要只数受害者 {#how-to-read}

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

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

## 值得先认出的事件 {#top-events}

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

## 阻塞者查询 {#blocker-query}

```sql
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;
```

## 常见误读 {#misreads}

- 被列为阻塞者的会话并不一定可以安全终止；它可能是维护业务不变量的唯一写入者。
- `transactionid` 不代表事务 ID 即将耗尽。
- `relation` 本身不说明具体关系；需要把 `pg_locks.relation` 关联到 `pg_class`。
- 增大 `lock_timeout` 只改变受害者等多久，并不会移除阻塞者。

---

本节页面：

- [Lock: advisory](/zh/lock/advisory/): 等待获取用户 advisory lock。
- [Lock: applytransaction](/zh/lock/applytransaction/): 等待获取逻辑复制订阅端正在应用的远程事务上的锁。
- [Lock: extend](/zh/lock/extend/): 等待扩展 relation。
- [Lock: frozenid](/zh/lock/frozenid/): 等待更新 pg_database.datfrozenxid 和 pg_database.datminmxid。
- [Lock: object](/zh/lock/object/): 等待获取非 relation 数据库对象上的锁。
- [Lock: page](/zh/lock/page/): 等待获取 relation 页面上的锁。
- [Lock: relation](/zh/lock/relation/): 等待获取 relation 上的锁。
- [Lock: spectoken](/zh/lock/spectoken/): 等待获取推测式插入锁。
- [Lock: transactionid](/zh/lock/transactionid/): 等待事务结束。
- [Lock: tuple](/zh/lock/tuple/): 等待获取 tuple 上的锁。
- [Lock: userlock](/zh/lock/userlock/): 等待获取用户锁。
- [Lock: virtualxid](/zh/lock/virtualxid/): 等待获取虚拟事务 ID 锁。
