PostgreSQL 如何用 pg_locks 查询当前所有锁信息

2次阅读

pg_locks视图返回当前正在持有或等待的锁状态快照,每行表示一个backend进程与锁对象(表、行、事务ID等)的关联关系;需联查pg_stat_activity才能获取进程和sql信息。

PostgreSQL 如何用 pg_locks 查询当前所有锁信息

pg_locks 视图返回的是什么数据

pg_lockspostgresql 内置的系统视图,它不存储锁的历史记录,只反映当前**正在持有或等待中**的锁状态。每一行代表一个锁对象(如表、行、事务ID等)与一个进程(pid)之间的关联关系。注意:它不是“谁锁了谁”的直观映射,而是“某个 backend 持有/等待某类锁”的快照。

如何查出带进程和 SQL 的完整锁信息

单独查 pg_locks 几乎没用,必须关联 pg_stat_activity 才能知道哪个会话在执行什么 SQL。常用组合查询如下:

SELECT    l.pid,   a.usename,   a.application_name,   a.client_addr,   l.mode,   l.granted,   l.locktype,   l.relation::regclass AS table_name,   l.page,   l.tuple,   a.state,   a.query FROM pg_locks l JOIN pg_stat_activity a ON l.pid = a.pid WHERE a.pid <> pg_backend_pid();

关键点:

  • l.granted = false 表示该进程正在等待锁(可能被阻塞)
  • l.locktype = 'relation' 对应表级锁,'tuple' 对应行级锁(需结合 pagetuple 定位)
  • a.state = 'active''idle in transaction' 的会话更值得关注
  • 过滤掉 pg_backend_pid() 是为了避免查到当前查询自身的锁(除非你故意要查)

为什么看不到行锁的具体 WHERE 条件

pg_locks 不保存 SQL 的谓词条件,它只记录锁作用的对象(比如第 5 页第 12 行),无法反推出 “WHERE id = 100” 这样的逻辑。如果你看到 locktype = 'tuple',只能确认有行锁存在,但具体锁了哪几行,得结合 query 字段里的 SQL + 表结构 + 当前事务的隔离级别来推理。

常见误区:

  • 认为 turtle 字段是行号 —— 实际是页面内的元组偏移,不是主键值
  • 试图用 pg_locks 查死锁源头 —— 它本身不体现等待链,需配合 pg_blocking_pids()pg_stat_activity.blocked_by(v13+)
  • 忽略事务未提交导致的长持锁 —— state = 'idle in transaction' 的会话常是隐形锁源

性能与权限注意事项

pg_locks 查询开销极小,但默认只对超级用户或拥有 pg_read_all_data(v14+)角色可见。普通用户即使被授权访问该视图,也只能看到自己 backend 的锁(pg_stat_activity 同理)。若需监控他人锁状态,必须由 dba 显式授权:

GRANT pg_read_all_data TO monitor_user;

另外,pg_locks 中的 pid 是 backend 进程 ID,不是操作系统 PID;重启 PostgreSQL 后所有锁清空,该视图也随之重置。

真正难的不是查锁,而是判断哪个锁不该长期存在、哪个 idle in transaction 其实卡在应用层没 commit —— 这些得靠 query 内容和业务上下文交叉验证。

text=ZqhQzanResources