AWR报告中定位Top SQL应优先关注“SQL ordered by Elapsed Time”中Elapsed Time per Exec (s) > 1的语句,结合Executions、CPU Time与Elapsed Time比值判断是否真慢或存在等待,再通过SQL ID查v$sql或dba_hist_sqltext获取完整语句及指定快照区间的执行计划。
如何从AWR报告中定位Top SQL耗时高的语句
awr报告里的“sql ordered by elapsed time”部分直接列出耗时最长的sql,但很多人没注意到:这个“耗时”是**该sql在采样周期内所有执行的总耗时(elapsed time)**,不是单次执行时间。如果一条sql执行了1000次,每次100ms,总耗时就显示为100秒——它可能根本不慢,只是调用频繁。
实操建议:
- 先看
Executions列:如果值很大(比如 >1000),再结合Elapsed Time per Exec (s)判断单次是否真慢; - 重点关注
Elapsed Time per Exec (s)> 1 的语句,这才是真正拖慢响应的候选; - 对比
CPU Time (s)和Elapsed Time (s):若后者远大于前者(比如2倍以上),说明存在严重等待(如I/O、锁、Latch),不是SQL逻辑问题,而是资源争用; - 报告中
SQL ID是关键,后续查v$sql或dba_hist_sqltext都靠它。
为什么用AWR查不到刚跑完的慢SQL?
AWR默认每60分钟自动快照一次,且保留8天(取决于DBA_HIST_SNAPSHOT配置)。这意味着:刚执行完的慢SQL,如果不在最近两个快照区间内,就不会被采集进AWR。
实操建议:
- 确认当前SQL是否在快照窗口内:查
select min(snap_id), max(snap_id) from dba_hist_snapshot; - 若需实时捕获,改用
v$sql视图:select sql_id, elapsed_time/1000000 as sec, executions, elapsed_time/executions/1000000 as avg_sec from v$sql where elapsed_time/executions > 1000000 order by avg_sec desc fetch first 10 rows only(注意除零保护); - 临时启用SQL Monitoring(需企业版+诊断包):
select * from v$sql_monitor where status = 'EXECUTING' or status = 'DONE (ERROR)' order by last_refresh_time desc。
查到SQL ID后,怎么快速拿到完整语句和执行计划?
AWR报告只显示SQL前1000字符,常截断关键WHERE条件或子查询。必须通过SQL ID反查原始文本和历史计划。
实操建议:
- 取完整文本:
select sql_text from dba_hist_sqltext where sql_id = 'xxx'(注意:dba_hist_sqltext可能不包含最新SQL,优先试v$sql); - 查历史执行计划:
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') order by timestamp desc; - 避免直接用
dbms_xplan.display_awr('sql_id'):它默认只显示最近一个快照的计划,可能不是你关心的那个时刻的;加参数begin_snap=>N, end_snap=>M显式指定区间; - 若
dba_hist_sqltext查不到,检查是否启用了STATISTICS_LEVEL = TYPICAL(BASIC会禁用AWR SQL采集)。
AWR Top SQL排序依据不同,结果差异很大
AWR报告提供多个“SQL ordered by…”页签,选错维度会误导优化方向。例如按“Buffer Gets”排序,高的是逻辑读多的SQL,未必耗时长;按“Rows Processed”排,可能只是大批量ETL作业——业务上合理,不该动。
实操建议:
- 性能瓶颈优先看
SQL ordered by Elapsed Time和SQL ordered by CPU Time; - IO压力大时看
SQL ordered by Physical Reads,但注意:全表扫描物理读高未必错,索引回表逻辑读高反而更伤; - 锁等待问题看
SQL ordered by User I/O Wait Time或Concurrency Wait Time; - 别只盯Top 5:有时第23条SQL的
Elapsed Time per Exec是8.2秒,而Top 1是0.9秒但执行了上万次——后者对整体负载影响更大。
AWR是快照汇总数据,丢失了SQL执行时的上下文(绑定变量值、会话状态、瞬时锁信息)。真要根因分析,得结合ASH(v$active_session_history)查具体哪一秒卡在哪一步。











