“SQL ordered by Elapsed Time”排名依据是总耗时(单次平均耗时×执行次数),非单次最慢SQL;高执行频次的普通SQL可能因此上榜,需结合Elapsed Time per Exec、CPU/Elapsed比值及等待事件综合判断。

“SQL ordered by Elapsed Time”不是单次最慢SQL排名
AWR报告里这个模块排的是「总耗时 = 单次平均耗时 × 执行次数」,不是你直觉里“哪条SQL跑一次卡了30秒”。比如一条SELECT /*+ FULL(t) */ COUNT(*) FROM orders每秒执行200次、每次80ms,总耗时就冲到Top 1;但它根本不算慢SQL,只是调用太密。
实操建议:
- 先看
Executions列:值 > 1000 的语句,别急着优化,先查Elapsed Time per Exec (s)是否 - 真正要盯的是
Elapsed Time per Exec (s) > 1且Executions ≤ 50的行,这类SQL单次执行已明显拖累响应 - 对比
CPU Time (s)和Elapsed Time (s):若后者是前者的3倍以上(如CPU=0.2s,Elapsed=0.7s),说明大量时间花在等待上,不是SQL写得差,而是enq: TX - row lock contention或log file sync这类事件在卡住
为什么高Buffer Gets的SQL可能根本不该优先处理
很多人一看到“SQL ordered by Gets”里某条SQL占了80%逻辑读,就认定它是罪魁祸首。但AWR不告诉你这80%是被1个用户执行了1次,还是被1000个用户各执行1次——前者要立刻查执行计划,后者可能只是个被缓存的配置查询。
实操建议:
- 交叉比对:如果某SQL在“Elapsed Time”里排前5,但在“Gets”和“Reads”里完全没上榜,大概率问题不在I/O,而在硬解析(查
parse_calls/executions是否 > 0.8)或DBLINK网络延迟(搜SQL文本里的@符号) - 警惕远程全表扫描:SQL文本含
TABLE ACCESS FULL+@,且Physical Reads≈Logical Reads,说明每次都在跨库拉整张表,优化方向是加远程统计信息或改用物化视图 -
DBA_HIST_SQLSTAT比报告更细:运行SELECT sql_id, plan_hash_value, executions, elapsed_time/executions/1000000 avg_sec FROM dba_hist_sqlstat WHERE sql_id = 'xxx' AND snap_id BETWEEN 12345 AND 12346 ORDER BY avg_sec DESC,能拿到分钟级波动,避开AWR一小时聚合的平滑假象
查到SQL ID后,怎么绕过AWR截断拿到完整语句
AWR报告默认只显示SQL前1000字符,而真实问题常藏在第1001位之后——比如WHERE status IN (SELECT ...)子查询被砍掉,你根本看不出它关联了几个大表。
实操建议:
- 优先查
v$sql:SELECT sql_text FROM v$sql WHERE sql_id = 'abc123xyz',它存的是内存中最近执行过的完整文本(注意v$sql会老化,查不到就换下面) - fallback到
dba_hist_sqltext:SELECT sql_text FROM dba_hist_sqltext WHERE sql_id = 'abc123xyz' AND piece = 0(piece=0保证取首段,避免拼接错误) - 执行计划别只信报告里的快照:用
SELECT * FROM dba_hist_sql_plan WHERE sql_id = 'abc123xyz' AND plan_hash_value = 1234567890 ORDER BY timestamp DESC FETCH FIRST 1 ROW ONLY,确认当前生效的plan是否和报告里一致——计划突变常导致同SQL性能雪崩
为什么刚执行完的慢SQL在AWR里找不到
AWR默认每60分钟打一次快照,且只保留最近8天数据。你下午3:05发现一条SQL跑了25秒,但3:00和4:00的两个快照里它都没出现——因为3:00快照没捕获它,4:00快照又还没生成。
实操建议:
- 实时排查用
v$sql:SELECT sql_id, sql_text, elapsed_time/executions/1000000 sec_per_exec FROM v$sql WHERE executions > 0 AND elapsed_time/executions > 1000000 ORDER BY sec_per_exec DESC FETCH FIRST 5 ROWS ONLY(加executions > 0防除零) - 正在跑的SQL看
v$sql_monitor(需企业版+诊断包):SELECT sql_id, status, first_refresh_time, last_refresh_time FROM v$sql_monitor WHERE status IN ('EXECUTING', 'DONE (ERROR)') ORDER BY last_refresh_time DESC,它能告诉你此刻哪条SQL卡在哪个步骤 - 别依赖AWR做故障复盘:关键业务系统应提前配置
DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS(retention => 43200)(保留30天),否则8天后连历史趋势都追不回
AWR本身不撒谎,但它的聚合逻辑会掩盖时间维度上的尖刺。真正卡住用户的,往往是一次性高延时事件,而AWR只给你一个“平均分”。所以永远要带着ASH和v$sql去交叉验证,而不是盯着HTML报告里的Top 10发呆。


















