ash是定位os cpu 100%时瞬时cpu热点的唯一有效视图,需用gv$active_session_history、where session_state = 'on cpu'及动态时间窗口sample_time > sysdate - interval '5' minute精准查询。

OS CPU 利用率 100% 时,Oracle 自身未必“卡死”,但很可能有会话在疯狂吃 CPU —— 这时别等 AWR 报告,v$active_session_history(ASH)是唯一能抓到瞬时热点的视图,它每秒采样一次,只要问题发生在最近 1 小时内,就能定位到具体 sql_id、会话甚至后台进程。
查 ON CPU 样本必须加 WHERE session_state = 'ON CPU'
ASH 里混着各种等待事件(enq: TX - row lock contention、db file sequential read 等),不加过滤会把 I/O 或锁等待误当成 CPU 问题。只统计真正消耗 CPU 的瞬间,才是准确排名的基础。
- 必须写
WHERE session_state = 'ON CPU',大小写敏感,不能写成'on cpu'或'On Cpu' - 别漏掉时间条件:
SAMPLE_TIME > SYSDATE - INTERVAL '5' MINUTE比SYSDATE - 1/24更稳妥,避免因 NLS 时区设置导致范围偏差 - RAC 环境务必用
gv$active_session_history,否则只看到当前节点,可能完全错过真实热点节点
SQL_ID 聚合计数比执行时间更可靠
ASH 不记录 SQL 执行总时长,只记录“被采样到正在 CPU 上运行”的次数。一个 SQL 被采样 50 次,说明它在过去几分钟内累计占了约 50 秒 CPU —— 这个频次就是实际负载强度,比 v$sql 里的 cpu_time 更实时、更抗老化干扰。
- 直接
GROUP BY sql_id计数,不要按sql_text聚合,绑定变量或格式差异会导致同一逻辑 SQL 被拆成多个条目 - 如果
v$sql查不到文本(sql_text IS NULL),立刻切到dba_hist_sqltext,但需注意:该视图依赖 AWR 快照,没开 AWR 或快照间隔太长(如 1 小时)就可能查不到 - 遇到
sql_id = '0000000000000000'或sql_text是SELECT /*+ rule */ FROM sys.undo$这类系统递归语句,大概率是 DML 触发的索引分裂或 undo header 更新,不是业务 SQL 本身,得结合program和module定位源头
别忽略 BACKGROUND 类型的 ON CPU 会话
业务连接全空、v$session 里几乎没活跃会话,但 OS CPU 还是 100%?这时候重点查 session_type = 'BACKGROUND' 且 session_state = 'ON CPU' 的样本,常见元凶是:ora_q000(队列监听)、cjq0(job 队列协调)、mmon(AWR 自动收集)、mmnl(轻量级监控)。
- 执行
SELECT program, COUNT(*) FROM gv$active_session_history WHERE session_type = 'BACKGROUND' AND session_state = 'ON CPU' AND sample_time > SYSDATE - INTERVAL '5' MINUTE GROUP BY program ORDER BY 2 DESC - 若
sql_id为空,说明不是某条 SQL 在跑,而是 Oracle 内部结构维护(如 buffer cache latch 争抢、shared pool 内存管理)在吃 CPU,此时要转向v$sysmetric(看CPU Usage Per Sec)和v$osstat(看NUM_CPUS、IDLE_TIME)交叉验证 - Oracle 11g 中
mmnl进程频繁 ON CPU 可能是统计信息自动收集任务卡住,可临时禁用:EXEC DBMS_STATS.LOCK_TABLE_STATS('SYS','X$KCBWDS')(慎用,仅诊断)
ASH 数据只保 1 小时,且采样非连续——你看到的“没数据”,往往是因为时间窗口没卡准,或者问题已过去 61 分钟。真要复盘,得靠 dba_hist_active_sess_history,但它依赖 AWR 快照频率;而实时抓取,永远要从 sample_time 的动态计算开始,不是写死时间字符串。











