07 · 等待事件与 OWI 方法:从 OSW 到 BUG 的完整破案实录

Oracle 性能诊断的核心思想叫 OWI(Oracle Wait Interface) ,一句话:会话要么在 CPU 上执行,要么在等待。把所有会话"等什么、等多久"统计起来,瓶颈就藏不住。本篇先给速查表和诊断 SQL 模板,再用一个"节点宕机"的真实案例,走一遍从系统日志到 MOS BUG 的完整破案流程。

一、OWI 的三个数据层级

层级 视图/工具 保留 用途
实时 v$session_wait / v$session 当前瞬间 "现在卡住了"
近期 v$active_session_history(内存) 约数小时 "刚过去的一小时"
历史 dba_hist_active_sess_history(AWR 底层) 随 AWR 保留(默认 8 天) 任意历史时段回溯

诊断习惯 :能实时看就用 v$session,需要历史区间就用 dba_hist_*,两者结构几乎一致。

sql 复制代码
-- 当前谁在等什么(实时三板斧)
SELECT sid, serial#, username, event, wait_class, sql_id, blocking_session
FROM v$session
WHERE state = 'WAITING' AND wait_class != 'Idle'
ORDER BY seconds_in_wait DESC;

-- 历史区间等待事件分布(换 sample_time 即可)
SELECT instance_number, event, COUNT(*)
FROM dba_hist_active_sess_history
WHERE sample_time BETWEEN TO_DATE('2026-08-14 12:00','yyyy-mm-dd hh24:mi')
                      AND TO_DATE('2026-08-14 12:16','yyyy-mm-dd hh24:mi')
GROUP BY instance_number, event
HAVING COUNT(*) > 50
ORDER BY 3 DESC;

ASH 里 COUNT(*) 的含义:采样次数 ≈ 该等待消耗的秒数(1 秒采一次)。2434 次采样 ≈ 约 40 分钟的 DB Time 耗在这个事件上。

二、常见等待事件速查表(按 wait_class 分组)

Application(应用层)

事件 含义 动作
enq: TX - row lock contention 行锁争用 \[09-锁阻塞与死锁排查]
enq: TM - contention 表级锁:DDL 撞 DML / 外键无索引 找 DDL 来源,外键建索引

Concurrency(并发)

事件 含义 动作
buffer busy waits 热块争用(段头/数据块) 反向键索引、分区打散、调 initrans
latch: shared pool / library cache: mutex X 硬解析过多 绑定变量(\[10-慢SQL分析路径])
cursor: mutex X / S 游标互斥:解析/子游标过多 见本篇案例
row cache lock 数据字典缓存争用(常见于密集 DDL) 查 DDL 来源

System I/O / Commit

事件 含义 动作
log file sync commit 等 LGWR 刷盘 \[08-log-file-sync提交慢专题]
log file switch (checkpoint incomplete) redo 太小/太少,切换卡住 加大 redo、加组
db file scattered read 全表扫多块读 SQL 加索引/改写
db file sequential read 索引单块读 看回表量、存储延迟
db file parallel write/read DBWR/IO 层 查存储与 OSW

Cluster(RAC 专属)

事件 含义 动作
gc buffer busy acquire/release 跨节点块争用 应用亲和性、反向键索引
gc cr block 2-way/3-way 跨节点构造 CR 块 查私网延迟

可以忽略的 Idle 类

SQL*Net message from client(等应用发指令)、ges generic event(RAC 空闲)等------先过滤 wait_class='Idle' 再分析,否则榜首永远是空闲等待

三、真实案例:16 分钟内存耗尽导致节点宕机

背景:一套 12cR2 RAC 生产库的真实故障。

3.1 案情

2024-06-17 12:30,12cR2 两节点 RAC 的节点二宕机,宕机前观察到内存耗尽。

3.2 第一步:OSW 圈定时间窗

OSW(OS Watcher)的 top 采样显示:

复制代码
12:00  free 内存 52,011,212 KB
12:10  free 内存 15,533,284 KB     ← 10 分钟掉 36 GB
12:16  free 内存  1,220,792 KB     ← 耗尽边缘
12:18  之后无采样(主机失联/宕机)

结论:故障酝酿期 12:00--12:16,16 分钟。

3.3 第二步:alert.log 定性

log 复制代码
ORA-16198: LGWR received timedout error from KSR        ← 先有网络层异常
ORA-00603: ORACLE server session terminated by fatal error
ORA-27300: OS system dependent operation:sendmsg failed with status: 105
ORA-27301: OS failure message: No buffer space available ← 内核无内存分配 socket

No buffer space available(errno 105 ENOBUFS):内存耗尽连 socket 缓冲区都分配不出,网络功能连锁崩溃------与 OSW 的内存曲线互相印证。命中 MOS Doc ID 2041723.1。

3.4 第三步:ASH 找元凶事件

对 12:00--12:16 窗口统计:

复制代码
INSTANCE  EVENT                                    COUNT(*)
2         cursor: mutex X                             2434   ← 一枝独秀
1/2       ges generic event                        384/360   ← 空闲,忽略
1/2       log file switch (checkpoint incomplete)  181/89    ← 次要:redo 偏小

3.5 第四步:锁定 SQL 并深挖游标

sql 复制代码
-- 哪条 SQL 贡献了 cursor: mutex X
SELECT sql_id, COUNT(*) FROM dba_hist_active_sess_history
WHERE event IN ('cursor: mutex S','cursor: mutex X')
GROUP BY sql_id HAVING COUNT(*) > 10;

-- 子游标数量核实(version count 报告)
SELECT * FROM TABLE(version_rpt('7gpjgqbvfghgv'));
-- 关键输出:
--   Sharable_Mem: 180,850,612 bytes   ← 单条 SQL 吃掉 172 MB 共享内存
--   Total Versions: 2594              ← 2594 个子游标!
--   BIND_EQUIV_FAILURE : 2589         ← 绑定变量等价性检查失败

-- 不共享原因核实
SELECT child_number, BIND_EQUIV_FAILURE
FROM v$sql_shared_cursor WHERE sql_id='7gpjgqbvfghgv';

破案 :SQL 带绑定变量,但自适应游标共享(ACS)机制与该版本优化器 BUG 相互作用,BIND_EQUIV_FAILURE 导致每执行几次就生成新子游标,16 分钟膨胀到 2594 个、共享内存 172 MB+,配合解析风暴把内存打爆。命中 BUG 28794230(MOS Doc ID 2539161.1)。

3.6 第五步:修复

临时缓解(无法停机时):

sql 复制代码
ALTER SYSTEM SET "_optimizer_use_feedback"=false SCOPE=SPFILE;
ALTER SYSTEM SET "_optimizer_adaptive_cursor_sharing"=false SCOPE=SPFILE;
ALTER SYSTEM SET "_optimizer_extended_cursor_sharing_rel"=none SCOPE=SPFILE;

根本修复:打补丁 28794230(支持滚动打补丁,RAC 可逐节点操作)。

系统层加固 (本案例主机直接宕机的教训):设置 vm.min_free_kbytes 为物理内存的 0.4%(本机 263 GB → 约 1,054,457 KB),给内核保留底仓,避免内存耗尽后整机失联。

3.7 案例复盘:方法论的价值

复制代码
OSW 圈时间窗 → alert.log 定性(内存/网络) → ASH 定位事件(cursor: mutex X)
→ 事件关联 SQL → version_rpt/v$sql_shared_cursor 找根因(子游标爆炸)
→ 比对 MOS 命中 BUG → 缓解 + 补丁 + 内核参数加固

五层递进,每层都有数据支撑------这就是 \[01-故障排查方法论与工具箱] 六步框架的完整落地。

四、日常监听等待事件的 SQL(巡检可用)

sql 复制代码
-- 实例启动以来的 Top 等待
SELECT event, total_waits, time_waited/100 sec_waited
FROM v$system_event
WHERE wait_class != 'Idle'
ORDER BY time_waited DESC FETCH FIRST 10 ROWS ONLY;

-- 当前阻塞链速览
SELECT sid, blocking_session, wait_class, event, sql_id
FROM v$session
WHERE blocking_session IS NOT NULL;

五、小结

  • OWI:会话非在 CPU 即在等待,统计等待即定位瓶颈;
  • 三层数据:v 实时 → vactive_session_history 近期 → dba_hist_* 历史;
  • 分析前先滤掉 Idle 类;
  • cursor: mutex X 案例展示标准破案链:OSW → alert → ASH → SQL → 游标 → BUG;
  • 系统层加固(vm.min_free_kbytes)与数据库修复同等重要。

下一篇:\[08-log-file-sync提交慢专题] ------ 把第一个高频等待事件拆到齿轮级。

相关推荐
Brilliantwxx1 小时前
【Linux】 进程(5) 僵尸进程与内存泄漏扩展
linux·运维·服务器·网络·c++
A.说学逗唱的Coke1 小时前
【数据库专题】ClickHouse 深度实战:从列式存储原理到 PB 级海量日志与可观测性分析
数据库·clickhouse·硬件架构
w01_02_031 小时前
虚拟机, ubuntu , samba
linux·运维·ubuntu
佳&弥1 小时前
数据库提权
服务器·数据库·安全·web安全·网络安全
渣渣盟1 小时前
Nginx 从零到上手:Windows & Linux 双环境教程
linux·windows·nginx
智购科技自动售货机工厂1 小时前
2026自动售货机电机驱动芯片选型:从L298N到DRV8870的工程实践~YH
大数据·开发语言·数据库·人工智能·单片机·嵌入式硬件·scikit-learn
Dola_Zou1 小时前
CodeMeter Linux 部署与配置指南
linux·运维·自动化·软件加密
MSTcheng.1 小时前
【Linux学习】Linux学习第二弹——Linux基本指令1
linux·运维·服务器·学习·指令
国科安芯1 小时前
ASL3159S:把精密信号的“破音“挡在切换之外的 0.9Ω 开关
服务器·网络·数据库·架构·状态模式·抗辐射加固