AWR报告中DB CPU Time过高不等于需优化Top SQL,须先验证其是否真实过高、高在何处及是否合理:需结合DB CPU占DB Time百分比与绝对值、主机CPU使用率、SQL CPU per Exec、执行计划稳定性及ASH采样综合判断。

AWR报告里DB CPU Time过高,不等于就要优化Top SQL——得先确认它是不是真高、高在哪、高得合不合理。
看DB CPU占DB Time比重和绝对值,别只扫Top 5 Timed Events
Top 5 Timed Foreground Events里DB CPU排第一,不代表CPU就是瓶颈。关键看两个数:
-
DB CPU占DB Time的百分比:如果只有30%,但DB Time是1200秒,说明实际CPU耗了360秒,是真实压力;如果占比45%但DB Time才20秒,大概率是采样噪音或低负载波动 - 绝对值是否匹配硬件能力:12核机器,1小时快照里
DB CPU显示3600秒,意味着平均每秒消耗1秒CPU(即1核满载);若显示43200秒,相当于平均每秒消耗12秒CPU(12核全满),这才是真正过载 - 对比
Host CPU使用率:AWR里%User Time+%System Time> 85%,且DB CPU/ (Host CPU (CPUs)× 快照时长) > 0.8,才能确认是数据库层CPU打满,不是OS其他进程抢资源
查SQL ordered by CPU Time时,重点筛CPU per Exec而非总CPU时间
总CPU时间高,可能是高频轻量SQL堆出来的,比如每秒执行200次、单次只耗5ms的语句,总时间碾压所有慢SQL,但它根本不需要优化。
- 过滤掉
EXECUTIONS = 0但CPU_TIME_SEC > 0的行——这是统计未刷新或游标异常终止的脏数据,直接忽略 - 优先关注:
CPU per Exec (s)> 1 且Executions> 10;或CPU per Exec (s)> 10(哪怕只执行1–2次) - 同一
SQL_ID在不同快照中PLAN_HASH_VALUE变了,说明执行计划不稳定——排名高可能只是某次劣化执行拉高均值,不能代表常态 - 用
DBMS_XPLAN.DISPLAY_AWR('<sql_id>', NULL, 'ALLSTATS LAST')查真实执行计划,重点看有没有NESTED LOOPS外层返回行数远超预估、FILTER操作卡在高Rows节点、或TABLE ACCESS FULL没走索引
当Top SQL合计CPU占比很低,问题往往不在SQL本身
如果DB CPU占比70%,但前10条SQL加起来只占总CPU的15%,说明大量时间耗在PL/SQL、递归调用或解析上。
- 查
v$sql里cpu_time/elapsed_time比值:若普遍偏低(如 - 用ASH按
session_state = 'ON CPU'聚合:SELECT sql_id, COUNT(*) FROM v$active_session_history WHERE session_state = 'ON CPU' AND sample_time > SYSDATE - 1/24 GROUP BY sql_id ORDER BY 2 DESC,能抓到实时“咬CPU”的SQL,不受AWR聚合失真影响 - 检查硬解析:看
Instance Efficiency Percentages里的Parse CPU to Parse Elapsd %,若低于20%,说明解析卡在latch争用;再查parse count (hard)/parse count (total),>10%就确认绑定变量漏了 -
buffer_gets_per_exec > 5000+rows_processed_per_exec很低 → 全表扫描缺索引;disk_reads_per_exec > 10000→ 物理I/O爆炸,优先查执行计划是否走了全表扫描
DBA_HIST_SQLSTAT必须补AWR默认视图的盲区
AWR报告只列Top 30 SQL,且不带PLAN_HASH_VALUE变化记录。很多性能抖动源于执行计划突变,但报告里看不出。
- 自己查
DBA_HIST_SQLSTAT:SELECT sql_id, plan_hash_value, executions, ROUND(elapsed_time / NULLIF(executions, 0) / 1000000, 2) AS ela_sec_per_exec, buffer_gets FROM dba_hist_sqlstat WHERE snap_id BETWEEN &begin_snap AND &end_snap AND executions > 100 ORDER BY ela_sec_per_exec DESC -
ela_sec_per_exec > 1且buffer_gets > 100000→ 基本可断定低效SQL - 同一
SQL_ID在不同快照里PLAN_HASH_VALUE变了,立刻查dba_hist_sql_plan对比差异,重点关注ACCESS_PREDICATES和FILTER_PREDICATES是否缺失、ROWS预估是否严重偏差 - 查完整SQL文本别只信
dba_hist_sqltext.sql_text:先试v$sql(SELECT sql_text FROM v$sql WHERE sql_id = 'xxx'),它存的是当前共享池最新完整文本;若查不到,再查dba_hist_sqltext.sql_fulltext(Oracle 11g+才有)
最易被忽略的是:AWR是聚合统计,它告诉你“总共花了多少CPU”,但不告诉你“哪一秒最卡”。真要定位瞬时尖峰,必须用ASH交叉验证——尤其当DB CPU高但Top SQL找不到明显元凶时,ON CPU采样才是唯一可信线索。


















