ON CPU 与 wait_class = 'User I/O' 不是并列关系,前者是 session_state 的取值,后者是等待事件分类;ASH 中无 wait_class = 'CPU',需用 session_state = 'ON CPU' 单独统计,并结合 foreground 过滤以准确分析 SQL 的 CPU 与 I/O 消耗。

ON CPU 和 wait_class = 'User I/O' 不是并列关系
ASH 里没有叫 wait_class = 'CPU' 的分类,ON CPU 是 session_state 的取值,不是等待事件,也不在 v$event_name 中。直接 WHERE wait_class = 'ON CPU' 永远查不到数据——这是最常踩的坑。
正确做法是把 session_state = 'ON CPU' 单独作为条件,和 wait_class IN ('User I/O', 'System I/O') 分开处理,再合并统计。否则你会漏掉所有真正耗 CPU 的会话。
-
session_state = 'ON CPU':表示该采样点正在执行指令,没等任何资源 -
session_state = 'WAITING'且wait_class = 'User I/O':表示它卡在磁盘读写上 -
session_state = 'WAITING'且event = 'log file sync':表面是等待,实际瓶颈可能在 LGWR 的log file parallel write,属于 I/O 链路下游
查 SQL 的 CPU vs I/O 时间占比必须加 foreground 过滤
不加 session_type = 'FOREGROUND',结果会被后台进程(如 CKPT、DBW0、LGWR)污染。这些进程本身就在做 I/O 或 CPU 工作,但它们的消耗不属于“用户 SQL 执行代价”。比如 LGWR 大量 log file parallel write 会拉高整体 I/O 比例,却和某条 SELECT 无关。
实操时,先用以下语句确认目标 SQL 在前台会话中的真实分布:
SELECT
sql_id,
CASE WHEN session_state = 'ON CPU' THEN 'ON CPU'
WHEN wait_class IN ('User I/O', 'System I/O') THEN 'I/O'
ELSE 'Other Wait' END AS category,
COUNT(*) cnt
FROM v$active_session_history
WHERE sql_id = 'c1x9m5k7n8v2q'
AND sample_time > SYSDATE - 1/48
AND session_type = 'FOREGROUND'
GROUP BY sql_id,
CASE WHEN session_state = 'ON CPU' THEN 'ON CPU'
WHEN wait_class IN ('User I/O', 'System I/O') THEN 'I/O'
ELSE 'Other Wait' END;User I/O 下的 event 名称不能直接等同于“慢磁盘”
看到 db file sequential read 就去查存储延迟,容易误判。这个事件单次等待长,更可能是索引块分散或 buffer cache 命中率低;而 direct path read 高频出现,说明数据根本没进缓存——得先看是不是大表扫描没走索引,而不是一上来就调优存储。
-
db file sequential read:平均等待 > 5ms → 查索引深度、leaf block 数、是否跨 ASM diskgroup -
db file scattered read:P3(读取块数)长期 -
direct path read:配合sql_plan_operation = 'PX BLOCK ITERATOR'看是否并行导致绕过 cache
INSERT 类 SQL 的“空白时间”要靠 wait_class 补全
SELECT 类 SQL 的 %CPU + %I/O ≈ 100%,但 INSERT 经常只占 40–60%。剩下那部分不是消失,而是落在 Commit、Configuration、Concurrency 这些 wait_class 里。
比如 log file switch (checkpoint incomplete) 属于 Configuration,enq: TX - row lock contention 属于 Application,它们都和写入逻辑强相关,但不会出现在 I/O 或 CPU 统计里。
所以分析 INSERT 性能,必须查:
SELECT wait_class, event, COUNT(*) FROM v$active_session_history WHERE sql_id = 'xxx' AND session_type = 'FOREGROUND' AND sample_time > SYSDATE - 1/24 GROUP BY wait_class, event ORDER BY COUNT(*) DESC;
忽略这些 wait_class,等于只看了半张性能图。尤其当 Commit 类占比突增,说明提交太频繁或日志写入被拖慢,而不是 CPU 或磁盘本身有问题。


















