由 John Doe 三月 30, 2026
PostgreSQL 长期以来缺少锁统计信息的收集能力,难以定位和优化业务层级的锁冲突相关的开销。

特性提交日志
在 pgstats 中新增锁统计信息支持。
本次提交新增了一种名为PGSTAT_KIND_LOCK的全新统计类型,实现了对锁标签(lock tags)的统计功能,统计维度与pg_locks视图保持一致。由于统计数据会根据LockTagType中的锁标签数量进行上限限制,因此该实现采用固定大小的存储结构。
该新增统计类型会记录以下字段,用于深入分析数据库锁行为,同时避免对性能关键代码路径(如快速路径锁获取)造成影响:
waits(等待次数)和wait_time(总等待时间):分别统计获取锁时需要等待的次数,以及等待获取锁的总耗时。这两项指标仅在锁成功获取后、且等待时间超过deadlock_timeout配置值时才会进行采集。fastpath_exceeded(快速路径超限次数):统计因max_locks_per_transaction配额限制,导致无法通过快速路径(fast path) 获取锁的总次数。
新增的pg_stat_lock视图可用于查询锁统计数据,配套提供了对应的 SQL 函数pg_stat_get_lock()。
讨论:https://postgr.es/m/aIyNxBWFCybgBZBS%40ip-10-97-1-34.eu-west-3.compute.internal
特性示例
新增系统视图pg_stat_lock包含三个关键指标如下:
| 指标名 | 类型 | 指标说明 |
|---|---|---|
waits |
bigint | 锁等待累计次数,仅当锁等待时间超过deadlock_timeout、且最终成功获取锁时才会累加,避免短等待的高频统计影响性能 |
wait_time |
bigint | 锁累计等待总时长,单位为毫秒,统计触发条件与waits一致,可精准量化锁等待对事务延迟的影响 |
fastpath_exceeded |
bigint | 因max_locks_per_transaction槽位限制,无法通过快速路径获取锁的累计次数,直接反映锁优化机制的失效情况 |
通过查询pg_stat_lock视图,可直接定位导致性能问题的锁类型,快速区分是行锁冲突、表锁冲突、事务 ID 锁冲突还是其他锁类型导致的问题,无需复现卡顿现场。
查看累计等待总时长最长的TOP5锁类型,定位核心瓶颈:
SELECT
locktype,
waits AS total_wait_times,
wait_time AS total_wait_ms,
round(wait_time::numeric / waits, 2) AS avg_wait_ms,
stats_reset
FROM pg_stat_lock
WHERE waits > 0
ORDER BY wait_time DESC
LIMIT 5;
查看事务 ID 锁与行锁的统计,判断是否存在长事务阻塞:
SELECT
locktype,
waits,
wait_time AS total_wait_ms,
round(wait_time::numeric / 1000 / 60, 2) AS total_wait_minutes
FROM pg_stat_lock
WHERE locktype IN ('transactionid', 'tuple');
若transactionid锁等待占比极高:说明存在长事务未提交,阻塞了其他事务的提交,优化方向为拆分长事务、避免空闲事务。
若tuple行锁等待占比极高:说明存在热点行并发更新冲突,优化方向为优化事务粒度、拆分热点数据。
若relation表锁等待占比极高:说明存在 DDL 与 DML 冲突、或全表扫描加锁,优化方向为调整 DDL 执行窗口、优化查询索引。
另外,PostgreSQL 的快速路径锁是针对轻量级表锁的关键优化,可将锁获取性能提升一个数量级,但该机制的生效上限由max_locks_per_transaction控制。此前 DBA 无法判断该参数是否配置合理,只能被动应对性能问题。
通过fastpath_exceeded指标,可直接量化快速路径锁的超限次数,精准判断是否需要调大max_locks_per_transaction参数,释放数据库的锁处理性能。
查看快速路径锁超限的锁类型与累计次数:
SELECT
locktype,
fastpath_exceeded
FROM pg_stat_lock
WHERE fastpath_exceeded > 0
ORDER BY fastpath_exceeded DESC;
若查询结果中relation锁的fastpath_exceeded数值持续增长,说明当前max_locks_per_transaction配置过小,导致快速路径锁频繁失效。
可在postgresql.conf中调大该参数(默认 64),建议按 2 倍梯度上调,重启数据库后生效,再次观察fastpath_exceeded是否停止增长。
该参数上调会增加每个事务的内存开销,建议最大不超过 1024,避免内存过度占用。
非常不错的体验,感谢所有参与的社区人员。
参考
提交日志:https://git.postgresql.org/pg/commitdiff/4019f725f5d43f37b23222d06d20e3da1038d373