导读:本期聚焦于关中王创作的《PostgreSQL中pg_stat_activity的wait_event_type是什么?如何用它快速诊断数据库阻塞?》,敬请观看详情。数据库突然卡住不动,一条UPDATE等了很久都没返回,遇到这种情况你会先查什么?PostgreSQL把每一个后端进程的等待信息都实时记录在pg_stat_activity视图里,其中wait_event_type字段标识了等待的大类,比如Lock、IO、LWLock等,而wait_event字段则给出了具体的等待事件。理解这两个字段的含义,就等于拿到了数据库性能诊断的第一手线索。本文将详细解读各类wait_event_type的含义与常见场景,梳理等待事件与锁阻塞之间的关系,并给出一套可以直接拿去用的阻塞诊断SQL模板,包括定位被阻塞会话、找出阻塞源头、查询锁队列等实用语句,帮助你把排查时间从半小时压缩到一分钟。

拿到一个卡住的数据库,最忌讳的做法就是凭感觉重启或者盲目杀进程。PostgreSQL其实早就在pg_stat_activity视图里把每个会话当前的状态、正在执行的SQL以及等待的事件都摆出来了,其中wait_event_typewait_event这两个字段是判断问题性质的关键。看懂它们,你基本就能判断出会话是在等锁、等磁盘IO,还是在等某个轻量级锁,进而选择正确的处置方式。

PostgreSQL中pg_stat_activity的wait_event_type是什么?如何用它快速诊断数据库阻塞?

一、wait_event_type字段详解:每种等待类型意味着什么

wait_event_type表示等待事件所属的大类,从PostgreSQL 9.6开始引入,到10以后覆盖面已经很完善。常见的取值包括Lock、LWLock、IO、Client、Extension、Timeout、IPC、Activity、BufferPin等。其中最需要重点关注的是下面几类。

Lock是重量级锁,也就是我们在pg_locks视图里看到的那种锁对象,比如表锁、行锁、事务ID锁、咨询锁。一旦看到wait_event_type是Lock,且wait_event是transactionid或tuple,基本可以断定这条会话在等另一个事务提交或回滚,属于典型的阻塞场景。而wait_event为relation时则说明在等表级锁,比如某条SELECT在大表扫描时被VACUUM FULL的AccessExclusiveLock挡住了。

LWLock是轻量级锁,主要用于保护共享内存中的内部数据结构,比如缓冲区映射表、WAL插入槽等。常见的有BufferContent、WALWrite、LockManager等。看到大量会话等WALWrite,通常说明WAL写入跟不上,可能是磁盘IO瓶颈;等BufferContent则可能与热点页争用有关。IO类事件直接说明进程在等磁盘操作,例如DataFileRead表示正在从数据文件读页,如果这类事件持续出现且读延迟高,大概率是缓存命中率低或者磁盘性能差。

Client类事件很容易被误解。wait_event_type='Client'state='idle in transaction'时,说明服务端在等客户端发下一条语句,问题往往出在应用代码里事务开着不提交,而不是数据库本身。Activity和Timeout一般不用太在意,比如WalWriterMain、CheckpointerMain这类后台进程的常规活动就归在这些类别里。

二、如何区分正常等待与真正的阻塞

并不是所有等待都有问题。一个健康的数据库里,pg_stat_activity中出现IO等待、Client等待都很正常,关键要看持续时间和影响范围。判断是否真的发生了阻塞,需要同时满足几个条件:多个会话的wait_event_type为Lock、被阻塞会话的state是active、并且等待持续时间超过了正常业务阈值。

一个实用技巧是结合query_startstate来判断。如果一条UPDATE的query_start已经停在五分钟前,state还是active,wait_event是transactionid,那它大概率在等一个持有行锁的事务。此时要找的不是这条UPDATE本身,而是那个持有锁却迟迟不提交的事务——它可能正以idle in transaction的状态挂在应用连接池里。

还有一点要注意:xact_startquery_start的区别。query_start是当前这条语句开始的时间,xact_start是事务开始的时间。如果一个会话xact_start很早但query_start是刚刚,中间隔了很久,说明这个事务里已经执行过多条语句,长时间持有锁,正是阻塞链的常见源头。

三、阻塞诊断SQL模板:从定位到处置

下面这套模板可以直接保存备用。第一条用来快速查看当前所有非空闲会话及其等待事件:

SELECT pid,
       usename,
       state,
       wait_event_type,
       wait_event,
       now() - query_start AS query_duration,
       left(query, 60) AS query_text
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY query_duration DESC;

第二条是经典的阻塞链查询,能直接显示谁阻塞了谁。借助pg_blocking_pids()函数(9.6及以上版本可用),一行就能拿到阻塞源头:

SELECT blocked.pid AS blocked_pid,
       blocked.usename AS blocked_user,
       left(blocked.query, 50) AS blocked_query,
       blocking.pid AS blocking_pid,
       blocking.usename AS blocking_user,
       blocking.state AS blocking_state,
       left(blocking.query, 50) AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
  ON blocking.pid = ANY (pg_blocking_pids(blocked.pid))
WHERE blocked.wait_event_type = 'Lock';

查到阻塞源头后,如果确认那个会话是异常的(比如应用崩溃后残留的idle in transaction连接),可以用下面两条语句处置。先温和地取消当前查询,不行再终止整个连接:

-- 只取消当前正在执行的语句,事务回滚由会话决定
SELECT pg_cancel_backend(12345);

-- 直接终止连接,未提交事务全部回滚
SELECT pg_terminate_backend(12345);

-- 批量终止所有空闲超过1小时的事务
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
  AND now() - state_change > interval '1 hour';

四、把诊断常态化:加个阈值告警和锁超时

与其等故障发生再手忙脚乱,不如提前设置两道防线。第一道是lock_timeout参数,建议在业务SQL的会话级别设置,例如SET lock_timeout = '5s',这样等锁超过五秒的语句会主动报错退出,避免请求堆积拖垮整个应用。注意不要全局设置过小的值,否则DDL操作容易被误伤。

第二道防线是idle_in_transaction_session_timeout,比如设置为10分钟,让那些忘记提交的事务自动被断开。很多诡异的生产阻塞,追根溯源都是应用里某个异常分支开了事务没关闭,这个参数能兜住大部分风险。

如果需要监控告警,可以基于前面的阻塞链查询改造:统计wait_event_type为Lock且等待超过30秒的会话数量,超过阈值就触发告警。把这个查询接入定时任务或Prometheus exporter,就能在用户投诉之前发现锁冲突。配合定期归档pg_stat_activity快照,还能在事后回溯阻塞发生时各会话的SQL,形成完整的故障复盘材料。

pg_stat_activitywait_event_typePostgreSQL阻塞诊断修改时间:2026-09-12 02:34:33

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