必须用sql*plus交互式执行@?/rdbms/admin/awrsqrpt.sql,禁用静默模式;sql id须从dba_hist_sqlstat精确查询,不可用v$sql模糊匹配;ora-01422源于非交互环境将prompt误作sql执行。
直接结论:必须用 sql*plus 交互式执行 @?/rdbms/admin/awrsqrpt.sql,不能静默调用;sql id 必须来自 dba_hist_sqlstat,不能靠 v$sql 模糊猜。
为什么 awrsqrpt.sql 总报 ORA-01422
这不是脚本有 bug,而是它被当成了“批处理”在跑。该脚本设计为交互式——每一步都依赖 SQL*Plus 的 prompt 输入。一旦放在非交互环境(比如 sqlplus -S / as sysdba @awrsqrpt.sql、SQL Developer 的“运行脚本”、或 shell 自动化管道),后续的 prompt 行(如 Enter value for report_type:)会被当成 SQL 执行,导致查询返回多行,触发 ORA-01422。
真正有效的做法是:
- 先用
sqlplus / as sysdba进入交互会话 - 再手动输入
@?/rdbms/admin/awrsqrpt.sql - 按屏幕提示依次输入:
html或text、DBID、实例号、起止快照 ID、SQL ID
SQL ID 必须从 dba_hist_sqlstat 查,不是 v$sql
v$sql 只存当前库缓存中的语句,重启、老化、刷新后就没了;而 awrsqrpt.sql 读的是 AWR 历史表,只认已落盘的 sql_id。如果凭印象或应用日志里的 SQL 片段去模糊匹配,大概率查不到或选错。
正确提取方式:
- 查最近 7 天执行次数最多的前 10 条 SQL:
SELECT sql_id, sql_text FROM dba_hist_sqlstat s JOIN dba_hist_sqltext t USING (sql_id) WHERE s.snap_id > (SELECT MAX(snap_id)-100 FROM dba_hist_snapshot) ORDER BY executions_delta DESC FETCH FIRST 10 ROWS ONLY; - 查某条具体语句的历史执行耗时:
SELECT snap_id, elapsed_time_delta/1000000 AS sec, buffer_gets_delta FROM dba_hist_sqlstat WHERE sql_id = 'c0yffdyps8uk9' AND snap_id BETWEEN 1679 AND 1680; - 别复制
sql_id时漏掉末尾的 0(比如把abc123456780看成abc12345678O)
HTML 报告打不开或乱码?优先切 text 模式
HTML 报告依赖 $ORACLE_HOME/rdbms/admin/awrrpt.css 和内嵌 JS 渲染图表。常见失效场景:
- 生成用户对
$ORACLE_HOME/rdbms/admin/目录无读权限(尤其 AIX/Linux 上 umask 导致 .css 不可读) - 双击 .html 文件用 file:// 协议打开,浏览器因跨域策略拒绝加载本地 JS
- Oracle Home 中缺失
oracle.sql.jar(影响图表数据解析)
临时绕过所有前端问题的方法:在第一步就输 text,生成纯文本报告。它不依赖任何外部资源,内容完整,关键指标(执行计划、IO、CPU、等待事件)全都有,适合快速定位问题。
报告里没看到执行计划?检查快照范围是否覆盖 SQL 实际执行时段
awrsqrpt.sql 不是“回放”SQL,而是聚合该 SQL 在指定快照区间内的所有历史执行样本。如果选的 begin_snap 和 end_snap 之间该 SQL 根本没执行过(或执行次数为 0),报告就会空白或只显示 header。
验证方法:
- 先确认快照时间是否合理:
SELECT snap_id, begin_interval_time, end_interval_time FROM dba_hist_snapshot WHERE snap_id IN (1679, 1680); - 再确认该 SQL 是否真在那个区间活跃:
SELECT COUNT(*) FROM dba_hist_sqlstat WHERE sql_id = 'c0yffdyps8uk9' AND snap_id BETWEEN 1679 AND 1680; - 如果 COUNT 为 0,说明要么 SQL 没跑,要么快照选错了——得往前翻快照,或查
dba_hist_active_sess_history确认真实执行时间点
最易被忽略的一点:AWR 报告本身不校验每条 SQL 在每个快照里是否真的被执行过。它只按 SQL ID + 快照范围做简单聚合。所以“选对快照”这件事,得 DBA 自己兜底,不能依赖报告自检。











