等待事件
简介
等待事件是指数据库中的进程或线程在执行过程中,由于某些资源不可用或需要等待某些条件满足而暂时无法继续执行的状态。
当一个事务或查询需要获取某个锁、读写磁盘、等待远程节点响应或访问共享内存结构时,就会进入“等待”状态。这些等待虽然短暂,但如果频繁发生或单次耗时过长,就会显著拖慢整体吞吐量。传统的性能监控往往只能看到某条 SQL 执行较慢,却无法定位慢的原因,这正是等待事件功能诞生的初衷。
GaussDB通过引入完善的等待事件体系,不仅记录了是否发生等待事件,还精确统计了“等待时长、等待次数及最长/最短/平均等待时间”,并支持按实例、线程、SQL 语句三个级别进行聚合分析,极大提升了系统可观测性和问题定位效率。总的来说,当客户作业不满足时延要求或者不满足客户预期时,等待事件功能可以方便运维人员及开发人员了解系统整体以及每个线程更详细的执行状态,辅助异常定位排查和系统优化。
原理
等待事件的设计理念是将等待行为视为一种可追踪、可聚合的时间片段。由于等待事件存在嵌套关系,因此通过栈式结构实现嵌套关系的自动上报与归因分析。整个等待事件的记录与统计依托于一个线程本地的等待事件栈,每一个工作线程(backend thread)在运行期间都维护着这样一个栈结构,用于跟踪当前正在发生的等待链路,等待事件功能原理如图1所示。
当线程进入一个需要等待的操作时(例如申请锁、读写文件、等待远程响应),系统会将当前操作所归属的等待事件压入栈顶。若此时栈中已有其他等待事件存在,则将栈顶等待事件的起始时间、等待时长等信息记录下来,并计入全局统计视图。
当等待事件结束,线程退出该等待状态时,栈顶事件被弹出,系统会记录该事件的完整耗时。若栈中仍有剩余事件,则将栈顶事件的开始时间更新为当前时刻,表明它仍在持续等待,从而维持等待链的连续性。
等待事件可分为以下四类:
- STATUS:表示执行关键代码段的等待,常见于耗时较长的同步操作或资源协调,例如:等待应用侧发数据(STATUS/wait cmd)、Pooler CN向DN建连(STATUS/pooler create conn)、GTM获取快照、SQL算子执行等。
- IO_EVENT:表示I/O操作的等待,当查询涉及大量数据扫描或大表访问时,该类等待事件值较大,典型场景包括读写HEAP文件、写WAL日志等。
- LWLOCK:用于保护内存结构的锁的等待,用于保护全局共享的内存结构,如全局共享的HASH表,常见于等待分区锁等场景。
- LOCK:数据库内部对象锁的等待,涵盖relation锁、tuple锁、事务锁等,当出现大量并发更新时,该类等待事件值较大。
示例
- 查看当前节点的等待事件统计信息。 WAIT_EVENTS使用详解,请参见《参考》中“Schema > DBE_PERF Schema > Wait Events > DBE_PERF.WAIT_EVENTS”章节。
--查看当前节点等待事件统计,包括每一类型等待事件的累计等待时间(total_wait_time)和平均等待时间(avg_wait_time)等。 gaussdb=# \x Expanded display is on. gaussdb=# SELECT nodename, type, event, wait, total_wait_time, avg_wait_time, last_updated FROM dbe_perf.wait_events ORDER BY total_wait_time DESC; -[ RECORD 1 ]---+--------------------------------------------- nodename | coordinator1 type | STATUS event | wait node wait | 393763 total_wait_time | 342584597958 avg_wait_time | 870027 last_updated | 2025-09-08 15:49:07.170297+08 -[ RECORD 2 ]---+--------------------------------------------- nodename | coordinator1 type | STATUS event | wait cmd wait | 351923 total_wait_time | 1438714213 avg_wait_time | 4088 last_updated | 2025-09-08 15:49:08.257995+08 -[ RECORD 3 ]---+--------------------------------------------- --More--
- 查看当前节点中各线程的等待阻塞情况。
PG_THREAD_WAIT_STATUS使用详解,请参见《参考》中“系统表和系统视图 > 系统视图 > 其他系统视图 > PG_THREAD_WAIT_STATUS”章节。
--查看当前节点中各线程的等待阻塞情况,wait_status字段表示当前线程正在等待的事件类型,例如wait_status字段为acquire lwlock时,表示正在等待获取轻量级锁、事务锁。 gaussdb=# \x Expanded display is on. gaussdb=# SELECT node_name, db_name, thread_name, tid, query_id, sessionid, lwtid, wait_status FROM pg_thread_wait_status; -[ RECORD 1 ]--------------------------- node_name | coordinator1 db_name | thread_name | jit compile worker tid | 140601850853120 query_id | 0 sessionid | 140601850853120 lwtid | 56358 wait_status | none -[ RECORD 2 ]--------------------------- node_name | coordinator1 db_name | thread_name | PageWriter tid | 140603134310144 query_id | 0 sessionid | 140603134310144 lwtid | 56261 wait_status | none -[ RECORD 3 ]--------------------------- --More--
- 查看FULL/SLOW SQL在执行过程中的等待事件。 STATEMENT_HISTORY使用详解,请参见《参考》中“系统表和系统视图 > 系统表 > 其他系统表 > STATEMENT_HISTORY”章节。
--查看FULL/SLOW SQL在执行过程中的发生的所有等待事件及其耗时。 gaussdb=# \x Expanded display is on. gaussdb=# SELECT query, unique_query_id, pg_catalog.statement_detail_decode(details, 'plaintext', true) FROM pg_catalog.statement_history; -[ RECORD 1 ]---+----------------------------------------------------------query | select gs_perf_do_shaking_collect(?); unique_query_id | 347666798 detail | ---------------Wait Events Area------------------ | '1' STATUS wait xact start command 139 (us) | '2' STATUS gtm get snapshot 125 (us) | '3' STATUS wait xact commit command 121 (us) | '4' IO_EVENT BufHashTableSearch 26 (us) | '5' STATUS flush data 11 (us) -[ RECORD 2 ]---+---------------------------------------------------------- --More--
注意事项
所有等待事件统计数据均保存在内存中的累积视图中,属于运行时状态,节点重启后清空。
