Oracle中如何通过AWR查看历史慢SQL的详细统计信息?
- 内容介绍
- 文章标签
- 相关推荐
本文共计935个文字,预计阅读时间需要4分钟。
相关专题
查AWR里执行时间最长的SQL用 dba_hist_sqlstat
awr快照中真正记录历史sql耗时的是 dba_hist_sqlstat,不是 v$sql(那是内存中当前缓存的)。关键字段是 elapsed_time_delta,单位微秒,需除以 1000000 转成秒。
常见错误是直接查 ELAPSED_TIME——它没做归一化,可能含多次执行叠加值;必须用带 DELTA 的列,代表该快照周期内增量耗时。
- 筛选慢SQL:加条件
ELAPSED_TIME_DELTA / 1000000 >= 2(2秒以上) - 避免漏掉低频但单次极慢的SQL:别只按
EXECUTIONS排序,优先按ELAPSED_TIME_DELTA降序 - 关联SQL文本要用
dba_hist_sqltext,注意sql_id可能为空(硬解析失败或被老化出共享池)
从AWR报告导出Top SQL要盯住“SQL Statistics”章节
生成AWR报告(awrrpt.sql)后,翻到“SQL Statistics”部分,里面分多个子表:SQL ordered by Elapsed Time、SQL ordered by CPU Time、SQL ordered by Gets 等。最常用的是第一个。
这里每条SQL带的“Elapsed Time per Exec (s)”是真实平均值,比手工算 v$sqlarea 更可靠——因为AWR已自动过滤掉异常抖动和采样偏差。
- 注意报告时间范围:默认是最近两个快照,可用
awrrpti.sql指定自定义起止snapshot_id - 如果SQL文本被截断(显示为“….”),在报告末尾的“SQL Statements”附录里找完整文本
- 同一
sql_id在不同快照中可能有不同执行计划,别假设它始终走同一条路径
用 dbms_xplan.display_awr 看历史执行计划
v$sql 里的执行计划随时可能被刷出内存,但AWR会持久化保存快照周期内的计划。调用 dbms_xplan.display_awr 才能还原当时真实走法。
典型命令:select * from table(dbms_xplan.display_awr('your_sql_id'));。不指定快照ID时,默认取该 sql_id 最近一次出现的快照。
- 如果返回空:说明该
sql_id没进过AWR(可能未启用统计收集,或快照间隔太长漏采) - 对比当前和历史计划差异时,重点看
Operation和Options列是否出现TABLE ACCESS FULL——这往往是索引失效或统计信息陈旧的信号 - 别依赖
PLAN_HASH_VALUE相等就认为计划一致:相同 hash 值下,Access Predicates或Filter Predicates可能已变
为什么 dba_hist_active_sess_history 有时比AWR更准?
当某条SQL执行超长(比如卡在锁或IO上),但它在快照周期内没完成,dba_hist_sqlstat 就不会记录其耗时——AWR只统计“已完成”的SQL。这时得靠 dba_hist_active_sess_history。
它按秒采样活跃会话,哪怕SQL没结束,只要在采样点处于 ACTIVE 状态,就会记一笔。查它能发现“正在发生但尚未落地”的慢查询。
- 关键过滤条件:
event = 'db file sequential read'或event like '%enq:%'(锁等待) - 结合
SAMPLE_TIME和sql_id,可定位到具体哪一秒卡在哪条SQL - 缺点是数据量大、查询慢,别无限制地
SELECT *,先用时间范围和用户过滤
AWR里看慢SQL,真正的难点不在查语句,而在确认“这个慢是常态还是偶发”。同一 sql_id 在不同快照里 ELAPSED_TIME_DELTA 差几倍很常见——得交叉比对 dba_hist_sqlstat、dba_hist_active_sess_history 和 dbms_xplan.display_awr 输出,才能排除采样误差和临时阻塞干扰。
本文共计935个文字,预计阅读时间需要4分钟。
相关专题
查AWR里执行时间最长的SQL用 dba_hist_sqlstat
awr快照中真正记录历史sql耗时的是 dba_hist_sqlstat,不是 v$sql(那是内存中当前缓存的)。关键字段是 elapsed_time_delta,单位微秒,需除以 1000000 转成秒。
常见错误是直接查 ELAPSED_TIME——它没做归一化,可能含多次执行叠加值;必须用带 DELTA 的列,代表该快照周期内增量耗时。
- 筛选慢SQL:加条件
ELAPSED_TIME_DELTA / 1000000 >= 2(2秒以上) - 避免漏掉低频但单次极慢的SQL:别只按
EXECUTIONS排序,优先按ELAPSED_TIME_DELTA降序 - 关联SQL文本要用
dba_hist_sqltext,注意sql_id可能为空(硬解析失败或被老化出共享池)
从AWR报告导出Top SQL要盯住“SQL Statistics”章节
生成AWR报告(awrrpt.sql)后,翻到“SQL Statistics”部分,里面分多个子表:SQL ordered by Elapsed Time、SQL ordered by CPU Time、SQL ordered by Gets 等。最常用的是第一个。
这里每条SQL带的“Elapsed Time per Exec (s)”是真实平均值,比手工算 v$sqlarea 更可靠——因为AWR已自动过滤掉异常抖动和采样偏差。
- 注意报告时间范围:默认是最近两个快照,可用
awrrpti.sql指定自定义起止snapshot_id - 如果SQL文本被截断(显示为“….”),在报告末尾的“SQL Statements”附录里找完整文本
- 同一
sql_id在不同快照中可能有不同执行计划,别假设它始终走同一条路径
用 dbms_xplan.display_awr 看历史执行计划
v$sql 里的执行计划随时可能被刷出内存,但AWR会持久化保存快照周期内的计划。调用 dbms_xplan.display_awr 才能还原当时真实走法。
典型命令:select * from table(dbms_xplan.display_awr('your_sql_id'));。不指定快照ID时,默认取该 sql_id 最近一次出现的快照。
- 如果返回空:说明该
sql_id没进过AWR(可能未启用统计收集,或快照间隔太长漏采) - 对比当前和历史计划差异时,重点看
Operation和Options列是否出现TABLE ACCESS FULL——这往往是索引失效或统计信息陈旧的信号 - 别依赖
PLAN_HASH_VALUE相等就认为计划一致:相同 hash 值下,Access Predicates或Filter Predicates可能已变
为什么 dba_hist_active_sess_history 有时比AWR更准?
当某条SQL执行超长(比如卡在锁或IO上),但它在快照周期内没完成,dba_hist_sqlstat 就不会记录其耗时——AWR只统计“已完成”的SQL。这时得靠 dba_hist_active_sess_history。
它按秒采样活跃会话,哪怕SQL没结束,只要在采样点处于 ACTIVE 状态,就会记一笔。查它能发现“正在发生但尚未落地”的慢查询。
- 关键过滤条件:
event = 'db file sequential read'或event like '%enq:%'(锁等待) - 结合
SAMPLE_TIME和sql_id,可定位到具体哪一秒卡在哪条SQL - 缺点是数据量大、查询慢,别无限制地
SELECT *,先用时间范围和用户过滤
AWR里看慢SQL,真正的难点不在查语句,而在确认“这个慢是常态还是偶发”。同一 sql_id 在不同快照里 ELAPSED_TIME_DELTA 差几倍很常见——得交叉比对 dba_hist_sqlstat、dba_hist_active_sess_history 和 dbms_xplan.display_awr 输出,才能排除采样误差和临时阻塞干扰。

