等待事件
简介
等待事件是指数据库中的进程或线程在执行过程中,由于某些资源不可用或需要等待某些条件满足而暂时无法继续执行的状态。
当一个事务或查询需要获取某个锁、读写磁盘、等待远程节点响应或访问共享内存结构时,就会进入“等待”状态。这些等待虽然短暂,但如果频繁发生或单次耗时过长,就会显著拖慢整体吞吐量。传统的性能监控往往只能看到某条 SQL 执行较慢,却无法定位慢的原因,这正是等待事件功能诞生的初衷。
GaussDB通过引入完善的等待事件体系,不仅记录了是否发生等待事件,还精确统计了“等待时长、等待次数及最长/最短/平均等待时间”,并支持按实例、线程、SQL 语句三个级别进行聚合分析,极大提升了系统可观测性和问题定位效率。总的来说,当客户作业不满足时延要求或者不满足客户预期时,等待事件功能可以方便运维人员及开发人员了解系统整体以及每个线程更详细的执行状态,辅助异常定位排查和系统优化。
原理
等待事件的设计理念是将等待行为视为一种可追踪、可聚合的时间片段。由于等待事件存在嵌套关系,因此通过栈式结构实现嵌套关系的自动上报与归因分析。整个等待事件的记录与统计依托于一个线程本地的等待事件栈,每一个工作线程(backend thread)在运行期间都维护着这样一个栈结构,用于跟踪当前正在发生的等待链路,等待事件功能原理如图1所示。
当线程进入一个需要等待的操作时(例如申请锁、读写文件、等待远程响应),系统会将当前操作所归属的等待事件压入栈顶。若此时栈中已有其他等待事件存在,则将栈顶等待事件的起始时间、等待时长等信息记录下来,并计入全局统计视图。
当等待事件结束,线程退出该等待状态时,栈顶事件被弹出,系统会记录该事件的完整耗时。若栈中仍有剩余事件,则将栈顶事件的开始时间更新为当前时刻,表明它仍在持续等待,从而维持等待链的连续性。
等待事件可分为以下四类:
- STATUS:表示执行关键代码段的等待,常见于耗时较长的同步操作或资源协调,例如:等待应用侧发数据(STATUS/wait cmd)、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 | datanode type | STATUS event | wait seq scan wait | 5393263 total_wait_time | 3608580930393 avg_wait_time | 669090 last_updated | 2025-09-08 15:07:25.21368+08 -[ RECORD 2 ]---+--------------------------------------------- nodename | datanode type | LWLOCK_EVENT event | BufMappingLock wait | 210299018 total_wait_time | 1447851453130 avg_wait_time | 6884 last_updated | 2025-09-04 15:43:52.573429+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 | datanode db_name | thread_name | jit compile worker tid | 140333940733696 query_id | 0 sessionid | 140333940733696 lwtid | 31151 wait_status | none -[ RECORD 2 ]------------------------------- node_name | datanode db_name | thread_name | PageWriter tid | 140335487383296 query_id | 0 sessionid | 140335487383296 lwtid | 31037 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) as detail FROM pg_catalog.statement_history; -[ RECORD 1 ]---+------------------------------------------------- query | SELECT * FROM sbtest1 WHERE c LIKE $1; unique_query_id | 137037933 detail | ---------------Wait Events Area--------- | '1' STATUS wait seq sca 5062119 (us) | '2' IO_EVENT DataFileRead 478437 (us) | '3' IO_EVENT BufHashTableSearch 131541 (us) | '4' IO_EVENT buffer_strategy_get 128778 (us) | '5' STATUS wait xact start command 44 (us) | '6' STATUS flush data 13 (us) | '7' IO_EVENT WALBufferAccess 0 (us) -[ RECORD 2 ]---+------------------------------------------------- --More--
注意事项
所有等待事件统计数据均保存在内存中的累积视图中,属于运行时状态,节点重启后清空。
