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提交慢专题] ------ 把第一个高频等待事件拆到齿轮级。

相关推荐
Ruiery2 小时前
Linux 6.6内核 CPU 深度解析(七):调度器启动 — 从单核到多核,调度器分阶段点亮
linux·运维·服务器
50万马克的面包2 小时前
CSDN-栈队列数组-知识点整理
linux·运维·服务器
Elastic 中国社区官方博客3 小时前
将你自己的密钥用于现有 Elastic Cloud 部署
大数据·数据库·elasticsearch·全文检索
红海云3 小时前
Jev:给智能系统做判断的模型
大数据·数据库·人工智能
wjkjpcba3 小时前
PCBA烧录程序是什么:PCBA包工包料厂家解析烧录与测试
linux·数据库·人工智能·smt贴片加工·pcba贴片加工厂
꯭自꯭闭꯭4 小时前
达梦事物特性及MVCC
linux·运维·数据库
小马同学-4 小时前
MySQL主从复制和读写分离
数据库·mysql
谢亮_vipxieliang4 小时前
Spring 事务失效的常见场景
java·开发语言·数据库·spring boot
今夕资源网4 小时前
OmniVoice 今夕整合包 本地语音TTS断网可用 修复了一些BUG 优化生成速度 极速秒生成
bug·语音克隆·omnivoice·断网可用·本地语音tts·语音tts
geovindu5 小时前
sql: JSON and XML Data Handling in SQL using sql server 2025
大数据·数据库·sqlserver·数据库开发·数据库架构