Oracle 11g CPU持续90%+且v$session无活跃会话时,应查v$active_session_history中session_type='BACKGROUND'且session_state='ON CPU'的记录,重点排查ora_q000/cjq0/mmon/mmnl等后台进程,因其自动维护任务(如AWR快照、统计收集、Job调度)可能引发高CPU;若ASH无SQL_ID,则需结合v$sysmetric和v$osstat分析底层CPU消耗,排除Oracle Bug或OS干扰。
查 v$active_session_history 看后台任务在忙什么
oracle 11g 中数据库看似空闲(无业务连接、v$session 里几乎没活跃会话),但 cpu 持续 90%+,大概率是后台进程在后台“偷偷干活”。这时不能只盯 v$session,得翻 v$active_session_history(ash)——它每秒采样一次活跃会话,哪怕只活了几十毫秒也会被捕获。
执行以下查询,聚焦非用户会话(session_type = 'BACKGROUND')且消耗 CPU 的记录:
SELECT sample_time, session_id, session_serial#, program, event, sql_id, sql_opname, p1text, p1, p2text, p2 FROM v$active_session_history WHERE session_type = 'BACKGROUND' AND session_state = 'ON CPU' AND sample_time > SYSDATE - 1/24 ORDER BY sample_time DESC;
常见高 CPU 后台任务包括:ora_q000_*(AQ Scheduler)、ora_cjq0_*(Job Queue Coordinator)、ora_mmon_*(Manageability Monitor)、ora_mmnl_*(Manageability Monitor Light)。它们不是 bug,而是 Oracle 自动维护机制在运行。
MMON 和 MMNL 在做自动内存/统计收集
Oracle 11g 默认开启自动内存管理(AMM)和自动统计信息收集(DBMS_STATS 任务),而 MMON 负责每小时一次的 AWR 快照 + 自动 SQL Tuning Advisor 分析,MMNL 则负责每分钟级的轻量级指标刷新(如 ASH buffer flush、AWR baseline 计算)。这两者在大库上极易触发大量解析、排序和内存扫描,尤其当:
-
STATISTICS_LEVEL = 'TYPICAL'(默认值,已足够触发全部后台采集) - 数据库刚重启,ASH buffer 积压未刷出,
MMNL突然批量 dump - AWR 快照间隔设得太短(如 15 分钟),或保留天数过长(如 60 天),导致
MMON扫描历史数据量暴增
验证方式:查 dba_scheduler_jobs 看是否启用了 ORA$AT_OS_OPT_SY_ 类自动调优任务;用 SELECT * FROM v$parameter WHERE name LIKE '%statistics_level%'; 确认当前级别。
CJQ0 被卡在调度大量 DBMS_JOB 或过期队列
如果系统仍使用老式 DBMS_JOB(而非 DBMS_SCHEDULER),CJQ0 进程可能因 job 队列堆积、job 执行失败未清理、或 job 内部逻辑含隐式全表扫描而持续占用 CPU。尤其注意:
- job 的
next_date设置为过去时间,导致反复重试 - job 执行的 PL/SQL 块中调用了未加索引字段的
SELECT ... FOR UPDATE,引发行锁等待链 + CPU 消耗 - 使用了
DBMS_ALERT或DBMS_PIPE等过时 IPC 机制,产生自旋等待
快速定位命令:
SELECT job, what, next_date, broken, failures, last_date FROM dba_jobs WHERE next_date 0;
若发现大量失败 job,别急着 DBMS_JOB.REMOVE,先查 dba_jobs_running 和 v$session_longops 看是否真有长任务卡住。
为什么 ASH 查不到 SQL 却 CPU 很高
这是最易被忽略的一点:ASH 只捕获“正在执行”的会话,但某些后台操作根本不出现在 sql_id 字段里——比如 MMON 做 AWR 快照时的内部元数据压缩、CKPT 进程刷检查点时的 buffer hash table 遍历、甚至 LGWR 在高并发下频繁写日志 buffer 的 spin lock 竞争。这些操作不走 SQL 引擎,不生成 sql_id,但真实消耗 CPU。
此时应结合 v$osstat 和 v$sysmetric 看底层指标:
SELECT * FROM v$sysmetric
WHERE metric_name IN ('CPU Usage Per Sec', 'Host CPU Utilization (%)')
AND intsize_csec > 0;
再比对 v$osstat 中 NUM_CPUS 和 IDLE_TIME,确认是 Oracle 进程真在用 CPU,还是 OS 层面其他进程干扰。真正难缠的,往往是那些既没 SQL、又没明显等待事件、却让单核跑满的“幽灵 CPU 消耗”——这通常指向 Oracle Bug(如 11.2.0.3 中已知的 MMON 内存泄漏),需打补丁或降级参数规避。











