要用 awrsqrpt.sql 查看单条 SQL 在多个快照区间的执行耗时趋势,必须启用其 multiple 模式并正确输入 sql_id、num_intervals 等参数,而非误用 awrrpt.sql;同时需结合 dba_hist_sqlstat 和 plan_hash_value 分析,避免混淆计划变更与真实性能问题。
用 awrsqrpt.sql 生成单条 SQL 的 AWR 报表,不是 awrrpt.sql
想看某条 sql 在多个快照区间里的执行耗时趋势,不能直接跑 awrrpt.sql —— 它只按时间范围出整体实例报告,sql 列表是汇总后的 top-n,不支持固定 sql+跨快照逐个对比。必须用 oracle 自带的 awrsqrpt.sql 脚本,它专为单条 sql 设计,能拉出指定 sql id 在任意两个快照之间(或多个连续区间)的详细执行统计。
常见错误是:在 SQL*Plus 里输 @?/rdbms/admin/awrrpt.sql,一路回车完发现报表里压根找不到目标 SQL,或者只有一行摘要,没法看出每次执行的 elapsed_time、cpu_time、buffer_gets 怎么变的。
- 确认 SQL ID 正确:从
v$sql或 AWR 视图查,别用 SQL 文本模糊匹配,大小写、空格、绑定变量都影响 ID 一致性 - 脚本路径要对:
@?/rdbms/admin/awrsqrpt.sql(11g+),旧版本可能是@$ORACLE_HOME/rdbms/admin/awrsqrpt.sql - 交互式输入时,“Enter value for sql_id:” 后必须填 13 位十六进制 ID,例如
7x2vzq6k9bq8f,不能填select * from t
指定多个快照区间要用 awrsqrpt.sql 的 “multiple” 模式
awrsqrpt.sql 默认只输出一个快照区间的报告(比如 snap_id 100 → 101)。要观察趋势,得让它跑多个相邻区间,比如 100→101、101→102、102→103……这时不能手动跑三次,得启用它的多区间模式。
操作上,在 SQL*Plus 中执行脚本后,当提示 “Enter value for report_type:” 时,输 html 或 text;到 “Enter value for num_days:” 时,**不要直接回车**——这里填天数只是快捷方式,真正控制区间数量的是下一步:“Enter value for inst_num:”,之后会问 “Enter value for num_intervals:”,这时填你想比的区间个数,比如 5,它就会自动往前推 5 个连续的快照对(默认每个区间 1 小时)。
- 若想自定义起始快照,把
num_days设为0,然后手动输begin_snap和end_snap,再设num_intervals,否则容易错位 - 注意快照间隔:如果数据库每 30 分钟采一次,但
num_intervals=5且没调num_days,它可能拉出跨度太小、数据稀疏的区间 - 输出的 HTML 报告里,每个区间是独立表格,关键列是
Elapsed Time (s)、Executions、Avg Elapsed Time (s),趋势就看这些数字怎么跳
dba_hist_sqlstat 手动查趋势更灵活,但要注意统计粒度和延迟
如果脚本输出太重、格式难解析,或者需要加条件筛选(比如只看 parse_calls > 1 的区间),直接查 dba_hist_sqlstat 更可控。这张表存的就是每个快照里 SQL 的聚合指标,一行一快照,SQL ID + snap_id 是联合主键。
但别直接 SELECT * FROM dba_hist_sqlstat WHERE sql_id = 'xxx' —— 缺少时间对齐,看不出“同一个 SQL 在相邻快照间的变化”。得用自连接或分析函数,比如:
SELECT s1.snap_id, s1.elapsed_time_delta / 1000000 AS elap_s, s1.executions_delta, ROUND((s1.elapsed_time_delta / NULLIF(s1.executions_delta, 0)) / 1000000, 3) AS avg_elap_s FROM dba_hist_sqlstat s1 WHERE s1.sql_id = '7x2vzq6k9bq8f' AND s1.snap_id IN (100, 101, 102, 103, 104) ORDER BY s1.snap_id;
这里容易踩的坑:
-
elapsed_time_delta是增量值,单位微秒,必须除1000000才是秒;executions_delta可能为 0,做除法前得NULLIF - 快照数据不是实时入库的,AWR 保留策略(如默认 8 天)和 MMON 任务延迟可能导致最新 1–2 个快照还没写入该视图
- 不同版本字段名有差异:11g 用
_delta后缀,12c+ 可能带_total字段,查前先DESC dba_hist_sqlstat
导出 CSV 做趋势图前,先确认执行计划是否稳定
报表里 Avg Elapsed Time 看着忽高忽低,第一反应不该是画折线图,而是查这期间执行计划有没有变。同一 SQL ID 对应多个 plan_hash_value,意味着优化器选了不同路径,耗时波动就不是“性能退化”,而是“逻辑变更”。
用下面语句快速核对:
SELECT DISTINCT plan_hash_value FROM dba_hist_sql_plan WHERE sql_id = '7x2vzq6k9bq8f' AND snap_id BETWEEN 100 AND 104;
如果返回多行,说明计划已漂移,后续所有耗时对比都得按 plan_hash_value 分组来看,否则拿哈希值 A 的 10ms 和哈希值 B 的 1200ms 放一起算“趋势”,结果毫无意义。
-
dba_hist_sql_plan不记录完整执行计划,只存 hash,要查具体 plan 得结合DBMS_XPLAN.DISPLAY_AWR - 绑定变量窥探、直方图变化、统计信息更新都会触发 plan_hash_value 变更,不是 DBA 改了 SQL 就叫“不稳定”
- 哪怕 plan_hash_value 相同,也要留意
io_interconnect_bytes或physical_read_bytes是否突增——可能只是存储层响应慢了
真正难的不是生成报表,是分清数字跳动背后是 SQL 本身的问题,还是环境抖动、计划切换、采样偏差这些干扰项。盯住 plan_hash_value 和 executions_delta 这两个字段,比盯着 elapsed_time_delta 有效得多。

















