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

来源:MySQL教程作者:董浩然头衔:网络博主
导读:本期聚焦于董浩然创作的《PostgreSQL 如何用 pg_locks 查询当前所有锁信息》,敬请观看详情。数据库突然卡住不动,一条UPDATE语句迟迟不返回,后面排队的请求越积越多,这类问题十有八九和锁有关。PostgreSQL 提供了系统视图 pg_locks,能够实时查看当前实例上所有锁的持有与等待情况,是排查锁冲突的核心工具。本文从锁的基本模式讲起,介绍 pg_locks 各字段含义,演示如何关联 pg_stat_activity 找出阻塞源头的会话,并给出查看行锁、锁等待链、以及安全终止阻塞会话的完整 SQL 示例,帮助你快速定位和解决生产环境中的锁问题。

PostgreSQL 的锁机制贯穿在表级访问、行级修改、事务提交等多个层面。当某个事务长时间持锁不放时,其他会话就会被阻塞,表现为接口超时、连接池耗尽甚至整个服务不可用。要排查这类问题,最直接的手段就是查询系统视图 pg_locks。它记录了当前实例上所有活跃锁的信息,包括谁持有什么锁、锁在哪个对象上、有没有会话正在等待。掌握它的用法,等于拿到了数据库内部的锁监控面板。

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

先理解锁模式:pg_locks 里的 locktype 和 mode 字段

在查询 pg_locks 之前,需要先弄清楚它记录的到底是什么。pg_locks 的每一行代表一个锁请求,既包括已经授予的锁(granted 为 t),也包括正在等待的锁(granted 为 f)。这不是一个只记录持有锁的视图,而是记录所有锁请求的视图,这一点很多人容易误解。

locktype 字段区分了锁的类型。最常见的是 relation(表级锁)、transactionid(事务ID锁)、tuple(行锁提示锁)、virtualxid(虚拟事务ID锁)以及 advisory(咨询锁)。行锁本身并不直接记录在 pg_locks 中,PostgreSQL 的行锁信息存储在行头部的 xmin/xmax 字段里,pg_locks 中的 tuple 类型锁只是一个轻量级的提示锁,用于指示某个事务正在对某行做修改操作。

mode 字段表示锁模式,从弱到强包括 AccessShareLock、RowShareLock、RowExclusiveLock、ShareUpdateExclusiveLock、ShareLock、ShareRowExclusiveLock、ExclusiveLock、AccessExclusiveLock。例如普通的 SELECT 会持有 AccessShareLock,INSERT、UPDATE、DELETE 持有 RowExclusiveLock,而 TRUNCATE、ALTER TABLE、DROP TABLE 会请求 AccessExclusiveLock,这也是最重的锁,会与几乎所有其他锁冲突。

基础查询:直接查看 pg_locks 视图内容

最简单的查询就是直接 select 全表,配合 pg_stat_activity 或系统函数把 pid 关联出来:

-- 查看当前所有锁请求的基本信息
SELECT
    locktype,
    database,
    relation::regclass AS locked_table,
    page,
    tuple,
    virtualxid,
    transactionid,
    classid,
    objid,
    objsubid,
    virtualtransaction,
    pid,
    mode,
    granted,
    fastpath,
    waitstart
FROM pg_locks
ORDER BY granted, pid;

几个关键字段的含义值得逐个说明。database 是数据库 OID,relation 是被锁对象的 OID,直接转成 ::regclass 可以显示表名,非常方便。virtualtransaction 和 pid 标识了锁属于哪个后端进程。granted 为 true 表示锁已授予,false 表示该会话正在等待这个锁。waitstart(PostgreSQL 14 及以上版本提供)记录了等待开始的时间,可以用来计算锁等待了多久。

注意 pg_locks 是系统视图,任何用户都可以查询,但它反映的是整个实例的瞬时状态,每次查询看到的都是查询执行那一刻的快照。如果锁冲突是间歇性出现的,可以配合定时轮询或者 log_lock_waits 参数记录锁等待日志。

实战:找出谁在阻塞谁,定位阻塞源头

单纯看 pg_locks 只能知道有哪些锁,真正排查问题时需要回答的问题是:哪个会话阻塞了哪个会话,源头是谁。这需要把 pg_locks 和 pg_stat_activity 关联起来。核心思路是:等待中的会话(granted = false)请求的锁,与某个已持锁会话(granted = true)在同一对象上、且模式冲突,那么后者就是阻塞者。

-- 查看被阻塞的会话及其阻塞源头
SELECT
    blocked.pid           AS blocked_pid,
    blocked_act.query     AS blocked_query,
    blocking.pid          AS blocking_pid,
    blocking_act.query    AS blocking_query,
    blocking_act.state    AS blocking_state,
    now() - blocking_act.xact_start AS blocking_xact_age
FROM pg_locks blocked
JOIN pg_stat_activity blocked_act
    ON blocked_act.pid = blocked.pid
JOIN pg_locks blocking
    ON blocking.locktype = blocked.locktype
   AND blocking.database IS NOT DISTINCT FROM blocked.database
   AND blocking.relation IS NOT DISTINCT FROM blocked.relation
   AND blocking.transactionid IS NOT DISTINCT FROM blocked.transactionid
   AND blocking.pid != blocked.pid
   AND blocking.granted
JOIN pg_stat_activity blocking_act
    ON blocking_act.pid = blocking.pid
WHERE NOT blocked.granted;

拿到阻塞源头的 pid 之后,可以进一步查看它的状态。很多情况下你会发现阻塞者的 state 是 idle in transaction,也就是事务开着却迟迟不提交,这通常是应用代码忘了提交或回滚,是生产环境中最常见的锁问题根源之一。

如果确认某个会话是问题源头,需要终止它,可以调用 pg_terminate_backend 函数。如果只想取消它当前正在执行的 SQL 而保留连接,用 pg_cancel_backend 更温和一些:

-- 取消阻塞会话当前正在执行的语句(连接保留)
SELECT pg_cancel_backend(12345);

-- 直接终止阻塞会话(强制断开连接,回滚其事务)
SELECT pg_terminate_backend(12345);

-- 一次性终止所有 idle in transaction 超过 5 分钟的会话
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
  AND now() - state_change > interval '5 minutes';

终止会话会回滚它未提交的事务,所有由它持有的锁随之释放,被阻塞的会话会立刻恢复执行。这也是处理锁问题时最立竿见影的手段,但操作前务必确认被终止的会话不是正在执行关键业务的正常事务。

进阶技巧:锁等待链与预防性配置

有时阻塞关系不是简单的一对一,A 等 B、B 等 C,形成等待链。PostgreSQL 9.6 及以上版本在 pg_stat_activity 中提供了 wait_event 和 wait_event_type 字段,wait_event_type 为 Lock 时表示会话正在等锁,配合 wait_event 的具体值(如 transactionid、relation、tuple)可以快速筛选出等锁会话:

-- 查看所有正在等待锁的会话及等待时长
SELECT
    pid,
    wait_event_type,
    wait_event,
    now() - query_start AS wait_duration,
    state,
    left(query, 60) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
ORDER BY wait_duration DESC;

从事前预防的角度,有几个参数值得关注。lock_timeout 可以设置语句获取锁的最长等待时间,超过就报错回滚,避免请求无限堆积;idle_in_transaction_session_timeout 可以自动终止长时间空闲的事务,从根源上减少锁泄漏;log_lock_waits 设为 on 后,任何超过 deadlock_timeout(默认 1 秒)的锁等待都会记录到日志,方便事后追溯。这三个参数组合使用,能大幅降低锁问题对生产环境的影响。

最后提醒一点,pg_locks 中的锁数据是瞬时的,排查偶发性锁冲突时,建议搭建一个简单的轮询脚本,每隔几秒把 pg_locks 和 pg_stat_activity 的快照落到一张日志表里,问题复现时就能完整还原当时的锁全貌,比事后凭空猜测要可靠得多。

PostgreSQLpg_locks锁查询修改时间:2026-09-06 20:38:42

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260906/51782.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。