sql ordered by cpu time 排名靠前的 sql 不一定真要优化,因其统计的是快照周期内累计 cpu 时间,而非单次效率;需交叉验证 cpu per exec 和执行频次,并结合 ash、v$sql 等实时视图综合判断。

直接看 SQL ordered by CPU Time 页面,但必须交叉验证 CPU per Exec 和执行频次,否则大概率误判——比如一条每秒跑 200 次、单次只耗 5ms 的 SQL,总 CPU 时间会碾压所有慢语句,但它根本不算“问题 SQL”。
为什么 SQL ordered by CPU Time 排名靠前的 SQL 不一定真要优化
AWR 的这个页面统计的是「该 SQL 在快照周期内所有执行累计消耗的 CPU 时间」,不是单次效率。常见误导场景:
-
EXECUTIONS极高(如 >10000),但CPU per Exec (s) -
EXECUTIONS = 0却有非零CPU_TIME_SEC:通常是游标异常终止或统计未刷新的脏数据,应直接过滤掉 - 同一
SQL_ID对应多个PLAN_HASH_VALUE:说明执行计划不稳定,此时排名高可能只是某次劣化执行拉高了均值,不能代表常态
怎么快速定位真正该盯的“CPU 密集型” SQL
重点不是总时间最长,而是单次执行对 CPU 的“咬合力”。实操建议:
- 在
SQL ordered by CPU Time表中,优先筛选满足以下任一条件的行:CPU per Exec (s) > 1且Executions > 10;或CPU per Exec (s) > 10(哪怕只执行 1–2 次) - 用
DBMS_XPLAN.DISPLAY_AWR('<sql_id>', NULL, 'ALLSTATS LAST')</sql_id>查其最近一次实际执行计划,重点关注:NESTED LOOPS外层返回行数是否远超预估、FILTER操作是否出现在高 Rows 节点、TABLE ACCESS FULL是否缺少索引支撑 - 对比正常时段 AWR 报告:若同一
SQL_ID的CPU per Exec突增 3 倍以上,基本可锁定为执行计划劣化(如统计信息陈旧、索引失效)
查到 SQL_ID 后,如何拿到完整语句和真实执行上下文
AWR 报告里只显示前 1000 字符,常截断关键条件。别直接信 dba_hist_sqltext.sql_text:
- 先试
v$sql:SELECT sql_text FROM v$sql WHERE sql_id = 'xxx'—— 它存的是当前共享池里的最新完整文本 - 若
v$sql查不到(已被 aged out),再查dba_hist_sqltext,但注意 Oracle 11g+ 才有sql_fulltext字段:SELECT sql_fulltext FROM dba_hist_sqltext WHERE sql_id = 'xxx' - 执行计划必须绑定快照区间:
SELECT * FROM dba_hist_sql_plan WHERE sql_id = 'xxx' AND plan_hash_value IN (SELECT plan_hash_value FROM dba_hist_sqlstat WHERE sql_id = 'xxx' AND snap_id BETWEEN &start_snap AND &end_snap)
最易被忽略的一点:AWR 快照是离散的(默认每小时一次),而 CPU 尖峰可能是秒级的。如果问题只持续几十秒,它很可能被平均掉、不体现在任何一份 AWR 报告里——此时必须切到 v$active_session_history 或实时 v$sql 辅助验证,不能只守着 AWR。











