\_awrsqrpt.sql 是 Oracle 内部未文档化脚本,用于在 SQL*Plus 中提取指定 SQL ID 在 AWR 快照区间的执行计划;需满足版本 ≥10.2.0.5、权限充足、SQL ID 准确且大小写敏感。
怎么用 _awrsqrpt.sql 提取单个 SQL 的 AWR 历史执行计划
这个脚本不是 oracle 官方支持的公开工具,而是 oracle 内部诊断包里一个未文档化的辅助脚本,常被 dba 用来快速拉出某条 sql 在多个快照区间内的执行计划对比。它不依赖 gui,纯 sql*plus 环境下就能跑,但必须满足几个硬条件:
- 数据库版本 ≥ 10.2.0.5(早期 10g 部分补丁缺失会导致报错
ORA-00904: "OTHER_XML" invalid identifier) - 当前用户有
SELECT_CATALOG_ROLE或直接授予了DBA_HIST_SQL_PLAN、DBA_HIST_SQLSTAT等视图权限 - SQL ID 必须准确——大小写敏感,且不能带空格或换行符;常见错误是复制时多了一个不可见的
\u200b(零宽空格)
执行命令长这样:
sqlplus / as sysdba @?/rdbms/admin/_awrsqrpt.sql
它会依次提示你输入:报告类型(文本/HTML)、起止快照 ID、DB ID、实例号、SQL ID。注意:SQL ID 是第 5 个参数,别填串了顺序;如果只记得 SQL 文本,得先查 SELECT sql_id FROM v$sql WHERE sql_text LIKE '%xxx%',但要注意 v$sql 只保留近期缓存,历史执行得靠 DBA_HIST_SQLTEXT。
SQL_ID 怎么算?为什么不同写法生成的 ID 不一样
SQL ID 是 Oracle 对 SQL 文本做 MD5 + Base32 截断后的 13 位字符串,对空格、换行、注释、绑定变量名都敏感。比如这两条语句:
SELECT * FROM emp WHERE deptno = :b1<br>SELECT * FROM emp WHERE deptno = :v_dept
哪怕逻辑完全一样,SQL_ID 也不同。更隐蔽的是隐式类型转换——WHERE id = '123' 和 WHERE id = 123(假设 id 是 NUMBER)会产生两个 SQL ID,因为字符字面量触发了 TO_NUMBER 转换,优化器视为不同语句。
所以查历史计划前,务必确认你手里的 SQL ID 来源可靠。常用验证方式:
- 从
AWR查:SELECT sql_id, sql_text FROM dba_hist_sqltext WHERE sql_text LIKE '%your_keyword%' - 从
ASH查最近活跃的:SELECT sql_id, COUNT(*) FROM v$active_session_history WHERE sample_time > SYSDATE - 1/24 GROUP BY sql_id ORDER BY 2 DESC - 用
DBMS_XPLAN.DISPLAY_AWR('<code>your_sql_id') 看是否能捞出至少一条计划,避免空跑_awrsqrpt.sql
执行 _awrsqrpt.sql 后输出为空或报 no rows selected 怎么办
这不是脚本坏了,大概率是数据断层或权限没到位。最常踩的坑是这三类:
- 目标 SQL 在指定快照区间内根本没执行过——AWR 默认每小时采样一次,若该 SQL 只在非整点执行(比如 10:17),而快照是 10:00 和 11:00,就可能漏掉;可放宽区间,或改用
DBA_HIST_ACTIVE_SESS_HISTORY按秒级查 - SQL 被刷出共享池太早,导致
DBA_HIST_SQLTEXT里没记录完整文本(只留sql_id和部分 hash);这时_awrsqrpt.sql因找不到原始文本而跳过 - 用户没有
SELECT权限访问DBA_HIST_*表,尤其在 12c+ 多租户环境下,必须确保连接的是 CDB$ROOT 且已GRANT SELECT ON CDB_HIST_SQL_PLAN TO your_user
一个快速验证方法:手动运行脚本里关键查询片段:
SELECT * FROM dba_hist_sqlstat WHERE sql_id = '<code>your_sql_id</code>' AND snap_id BETWEEN 1000 AND 1100;
如果这条都查不到,后面所有步骤都是白忙。
输出的 HTML 报告里执行计划字段含义和怎么看性能拐点
报告中每个快照对应的计划下面,重点关注这几列:
-
ELAPSED_TIME_TOTAL:总耗时(微秒),看趋势比看单次值更有意义;连续 3 个快照翻倍增长,基本可定位为性能退化起点 -
BUFFER_GETS_TOTAL:逻辑读,突然飙升常意味着走了全表扫描或嵌套循环失控 -
PLAN_HASH_VALUE:同一 SQL ID 下该值变化,说明执行计划变了;但注意:相同PLAN_HASH_VALUE不代表计划真的一样(OTHER_XML里可能藏了自适应计划分支差异) -
IO_INTERCONNECT_BYTES:RAC 环境下跨节点传输量,异常高说明 SQL 没做好数据本地化
真正难判断的是“计划没变但变慢了”。这时候要往下挖:DBA_HIST_SQLBIND 看绑定变量值是否变化导致选择性误判,或者用 DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST') 对比当前执行的实时统计。
别指望 _awrsqrpt.sql 给出根因——它只是把 AWR 里存的快照切片打包扔给你。真正的分析还得靠人盯住 PLAN_HASH_VALUE 变动时刻、绑定变量值、以及对应快照时间点的系统负载(CPU、I/O、内存压力)交叉比对。










