这期分享,源自我们重庆思庄在实际运维中经常被问到的一个高频问题:客户业务系统突然变慢,远程上去第一件事就是想先拉一份 AWR 报告看看趋势,可不少兄弟还在慢慢点 Enterprise Manager,或者打开 SQL*Plus 手动敲脚本,等报告出来业务高峰早都过去了。其实,Oracle 生成 AWR 报告本身就不该是个慢活儿,关键是你要把流程吃透,把该避的坑都避开,才能做到“一分钟出报告,报告出来就能看出个大概”。
这篇内容我会完整梳理 Oracle AWR 报告的快速生成方式,从快照原理、报告生成命令、常见报错到自动化思路一次讲透,适合刚从安装部署入门、需要自己做性能分析的使用者,也适合那些已经写过不少报告但偶尔被各种环境差异卡住的 DBA 同行。文章里所有命令我都基于 11g、12c、19c 做过验证,部分语句在更高版本同样适用,可以放心参考。
1. 先说清楚:为什么你总觉得生成 AWR 报告“不够快”
很多人对 AWR 报告的第一印象是“要等很久”,但等你把生成过程拆开看,就会发现真正耗时的从来不是报告生成那几秒,而是前面这些环节:
第一,快照时间窗口没选对。AWR 报告本质上是基于两个快照之间的采集数据做对比分析,如果你指定的起止快照时间跨度太大,比如从早上八点到晚上十点,那报告里的数据会被大量空闲时段稀释,看不出来问题;如果跨度太小,比如前后两个快照只隔五分钟,那很多时候统计信息还没凑够,同样没有分析价值。快照选得不合适,报告生成出来也白搭。
第二,很多人习惯打开 EM 网页控制台去点。不可否认,图形界面在某些场景下直观,但在生产环境尤其是数据库负载已经很高的时候,EM 自身是共享数据库资源的,你开一个页面就要多一组查询,要是数据库已经处于“喘不过气”的状态,打开 EM 可能都要半天。而且 EM 有时还会因为 agent 状态、权限配置等问题连不上,反而耽误事。
第三,如果数据库链接字符串、tnsnames 配置、用户权限这些基础项没搞清楚,你会反复卡在连接不上、权限不足这些报错上。等你在那一步步排查环境的时候,时间早就过去了。
所以,要做到“快速”,核心不在于手速,而在于你清楚整条链路:快照状态确认、报告类型选择、文件生成位置、内容快速解读。这篇后面就会按这个链路往下拆,每一步我都会补充实际运维中总结的经验。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. AWR 报告快速入门:快照的本质与生命周期管理
在真正开始手敲命令之前,建议先把 AWR 快照这套机制在脑子里过一遍。很多人会用 AWR 但说不清楚快照是什么时候创建的、能保留多久、为什么有时候手动执行创建快照会报错,这些坑我都踩过,这里一次讲清楚。
2.1 快照到底在采集什么
AWR 快照采集的核心,是数据库内部一系列性能统计视图的快照数据,比如会话活动、SQL 执行次数、等待事件、系统统计信息、段统计信息等。快照不是把整个数据库“拍照”备份,它采集的是一组与性能相关的计数器数值。每两个快照之间的差值,就是这段时间内数据库的真实活动情况。
这个设计思路有点像你家的电表:月初抄一次数字,月末再抄一次数字,差值就是你这个月用了多少电。AWR 报告就是通过两次“抄表”来还原数据库在某个时间段经历了什么。
数据库从 10g 开始默认开启 AWR,默认每个小时自动生成一个快照,快照在默认配置下保留 8 天。你可以通过以下方式查看当前数据库的快照频率和保留策略:
sql复制SELECT snap_interval, retention
FROM dba_hist_wr_control;
这里查出来的结果一般是这样:
| 参数 | 默认值 | 含义 |
|---|---|---|
| SNAP_INTERVAL | +00000 01:00:00.0 | 每 1 小时采集一次快照 |
| RETENTION | +00008 00:00:00.0 | 快照保留 8 天 |
| TOPNSQL | 30 | 默认采集 Top SQL 数量限制 |
2.2 手动创建快照的适用场景
自动快照颗粒度是 1 小时,理论上你生产环境每小时都留有采样点,但遇到下面这几种场景,手动创建快照就非常有必要:
场景一:业务方反馈“刚才那十几分钟系统特别卡”,现在已经恢复了。如果你不提前留快照点,等系统恢复后再去查,自动快照可能把“卡顿段”和“恢复段”混在同一个小时内,报告就看不出来当时的异常。这时候你应该在业务异常开始时立刻执行一次手动快照,等异常结束后再执行一次手动快照,两个快照就能精确定位异常窗口。
场景二:你准备做一次大的配置变更,比如调整 shared_pool 大小、加索引、修改 optimizer 模式。变更前打一个快照,变更后跑一段时间再打一个快照,这个对比报告就是你判断变更是否生效、有没有引入新问题的直接依据。
手动创建快照的命令只有一行:
sql复制EXEC dbms_workload_repository.create_snapshot();
执行完之后查一下最新的快照:
sql复制SELECT snap_id, begin_interval_time, end_interval_time
FROM dba_hist_snapshot
ORDER BY snap_id DESC
FETCH FIRST 5 ROWS ONLY;
这里提醒一下:不同 Oracle 版本对 FETCH 语法的支持不太一样,12c 及以后支持 FETCH FIRST,11g 可以用 ROWNUM <= 5 代替,我平时在两个版本间切换会注意这一点。
2.3 快照生命周期管理:保留策略与清理
生产库快照默认保留 8 天,8 天之前的历史快照会被自动清理。但有些场景下你要做长时间的性能对比,比如月底复盘整个月的趋势,你会发现 8 天根本不够。这时候需要修改保留策略:
sql复制BEGIN
dbms_workload_repository.modify_snapshot_settings(
retention => 43200, -- 单位是分钟,43200分钟即30天
interval => 30 -- 每 30 分钟采集一次
);
END;
/
修改完可以再用第一段里的查询确认一下生效情况。生产环境修改采集频率要慎重,快照间隔越短,AWR 表里的数据量增长越快,对 SYSAUX 表空间占用也会增加。如果 SYSAUX 空间本来就紧张,可能触发 Space 相关的告警,这块后续在常见问题里我会再展开讲。
3. 生成 AWR 报告的主流方式与选型对比
快照攒好了,接下来就是真正生成报告。很多人习惯直接敲 awrrpt.sql 脚本,但这只是其中一条路。我把实际工作中常用到的几种方式整理出来对比了一下,方便你根据场景选择。
3.1 命令行交互式执行 awrrpt.sql,最通用的做法
这是绝大多数 Oracle 手册里会写到的标准方法,也是我在客户服务器上最常用的应急手段。11g、12c、19c 的白名单机制下,脚本路径基本一致,但要注意统一放在 $ORACLE_HOME/rdbms/admin 目录下。
操作流程在命令行里就是:
sql复制sqlplus / as sysdba
SQL> @?/rdbms/admin/awrrpt.sql
执行时会依次提示你输入:
- 报告类型:
html还是text。一般做分析用 html,格式丰富、图表清晰;text 格式则在纯字符终端、需要把报告贴进邮件或脚本处理时更方便。 - 报告的天数范围:默认是
-1表示最近一天,也可以输入-2表示最近两天,或者直接回车接受默认。 - 起始快照 ID:列表会把当前可选范围内快照 ID、开始时间和结束时间都列出来,选一个靠前的。
- 结束快照 ID:一般比你选的起始快照大一些,确保时间段覆盖你关心的业务窗口。
- 报告文件名:如果不输会使用默认的
awrrpt_1_100_101.html这样带快照 ID 的名字;也可以自己指定,例如/tmp/awr_biz_peak.html。
走完这一通交互,脚本会去 dba_hist_* 数据字典里取数据,在本地生成报告。整个生成过程通常在 10 秒到 1 分钟不等,取决于快照间的数据量。如果选了异常大的时间段,比如跨 7 天,生成时间会明显变长,有时需要几分钟,但绝大多数场景不至于卡死。
3.2 非交互式脚本,适合远程和批量操作
很多 DBA 不喜欢交互式脚本,因为输入步骤多、容易出错,但我个人觉得交互式最大的问题在于输出信息很多,如果你用 SSH 工具连接,屏幕缓冲区可能不够,导致看漏了快照列表。所以后来我更多采用非交互式生成的方式:提前写好 SQL*Plus 脚本,把参数直接传进去。
先准备一个构建脚本,比如命名为 gen_awr.sql:
sql复制-- 变量定义
DEFINE report_type = 'html';
DEFINE num_days = -1;
DEFINE begin_snap = 100;
DEFINE end_snap = 120;
DEFINE report_name = '/tmp/awr_custom_report.html';
-- 执行报告生成
@?/rdbms/admin/awrrpti.sql
注意,这里用的不是 awrrpt.sql,而是 awrrpti.sql,这个“i”代表 instance,多了一个数据库实例 ID 参数。如果是单实例环境,两者差别不大;如果是 RAC 环境,你可能会想分别生成某个节点或者整个数据库的报告,这就要靠 awrrpti.sql 里输入实例号来区分了。
还有一份更常用的写法是直接调用 awrrpt.sql 配合 here-document 来避免手动输入。在 Linux 环境下可以这样:
bash复制sqlplus / as sysdba <<EOF
@?/rdbms/admin/awrrpt.sql
html
-1
100
120
/tmp/awr_report.html
EOF
它会按照顺序把参数传给脚本。但这里坑也不少:不同版本下 awrrpt.sql 的提示顺序完全一致,一般不会出错,但如果你指定的快照 ID 不存在,脚本会报错并终止。所以稳妥的做法是先把快照列表查询出来,确认好起止快照 ID 再丢进去生成。
3.3 通过 EM 云控 / 命令行 EM 生成,适合远程图形化操作
如果你在用 Oracle Enterprise Manager 13c 云控管理多套库,那从 EM 界面生成 AWR 报告也很方便:登录 EM,进入到数据库目标主页,选择“性能”→“AWR 报告”,填好起止快照,点生成即可,浏览器会直接渲染出 HTML 格式报告。
但我个人建议,EM 生成方式更适合管理者做展示和定期巡检,不适合故障应急。故障现场第一选择永远是 SQL*Plus,因为你少走一层 Web 逻辑,少依赖一个 agent,命令执行就是执行,不依赖中间件状态。
如果是非 RAC 的单实例,还有一条路径就是进入到 EM 的命令行 emctl 去看一些状态,但生成 AWR 报告真正调用的还是数据库内部包,没有捷径。
3.4 使用 dbms_workload_repository 包直接生成(RAC 环境推荐)
如果说 awrrpt.sql 是手工交易的“收银台”,那 dbms_workload_repository 包就是“金库直通门”。RAC 环境下,如果你想跨节点看整个数据库的性能,或者不想去终端交互式地回答问题,用存储过程包能灵活不少。
常用的就是 report_analysis 系列里面的函数:
sql复制SELECT
dbms_workload_repository.awr_report_html(
l_dbid => 1234567890,
l_inst_num => 1,
l_bid => 100,
l_eid => 120
)
FROM dual;
但这种查询方式直接返回 CLOB,在命令行窗口会被截断显示,真正实用的做法是把输出写入文件,下面这段是我在 19c RAC 环境验证过的方法:
sql复制SET LONG 2000000
SET LONGCHUNKSIZE 2000000
SET LINESIZE 300
SET PAGESIZE 0
SET TRIMSPOOL ON
SET FEEDBACK OFF
SPOOL /tmp/awr_rac_report.html
SELECT
dbms_workload_repository.awr_report_html(
l_dbid => (SELECT dbid FROM v$database),
l_inst_num => 1,
l_bid => 100,
l_eid => 120
) AS report_content
FROM dual;
SPOOL OFF;
RAC 多节点下,l_inst_num 传不同值可以分别生成各节点报告。如果想生成整个数据库的 RAC 报告,awr_report_html 参数那块不能省,你需要带着 dbid 和 inst_num 一起判断,或者用 awr_group_report_html 函数。
3.5 生成方式对比小结
为了照顾不同阶段的读者,我把这几种方式的核心差异列成一个表格:
| 方式 | 适用环境 | 复杂度 | 优点 | 缺点 |
|---|---|---|---|---|
| awrrpt.sql 交互式 | 单实例 / RAC | 低 | 通用性最好,官方标准,基本所有版本都有 | 需要手动交互,输出多 |
| awrrpti.sql + DEFINE | 单实例 / RAC | 中 | 自定义能力强,可指定实例号,适合脚本封装 | 需要提前知道参数,变量名不熟的话容易写错 |
| here-document 传参 | Linux 单实例 | 中 | 一条命令出报告,便捷 | 提示顺序依赖版本,快照 ID 错会直接跑失败 |
| EM 界面 | 大规模托管 | 低 | 图形化展示直观,可定期生成 | 依赖 EM 环境,故障时不推荐 |
| dbms_workload_repository | RAC / 特殊需求 | 高 | 最底层,灵活度最大,可嵌入应用 | 需要自己处理输出与格式问题 |
这几种方式没有绝对的优劣,我的建议是把前两种都熟练记住,再到 RAC 环境练熟最后一种,日常巡检用 EM,故障应急用命令行,基本不会慌。
4. 实操全流程:手工生成 AWR 报告的每一步应该这样卡时间
很多新手第一次跑 awrrpt.sql 会被脚本打印出来的一大串信息吓到,其实不用紧张,抓住流程的关键节点就清晰了。下面我就带你走一遍,告诉你在每一步你应该看到什么、该输入什么以及常见的坑。
4.1 检查权限与连接方式
AWR 报告的生成通常需要 DBA 角色,或者至少要有 SELECT_CATALOG_ROLE 和 ADVISOR 相关权限。你如果用普通业务账号去执行这脚本,十有八九会遇到权限报错。实际操作前可以先确认一下当前用户:
sql复制SELECT user FROM dual;
SELECT * FROM user_role_privs WHERE granted_role IN ('DBA','SELECT_CATALOG_ROLE');
如果输出为空或者没有 DBA,那就换系统用户去执行。生产环境我一般用 sysdba 登录,避免因为角色不够而卡住。不过也提醒一句:不要拿着业务账号去尝试生成 AWR,这是安全规范,也是效率问题。
4.2 准确定位目标快照范围,这一步最关键
前面说过,快照选得好不好直接决定报告的价值。正常情况下,你会先查一下有哪些快照可用:
sql复制SELECT snap_id,
TO_CHAR(begin_interval_time, 'YYYY-MM-DD HH24:MI') AS begin_time,
TO_CHAR(end_interval_time, 'YYYY-MM-DD HH24:MI') AS end_time
FROM dba_hist_snapshot
WHERE begin_interval_time >= SYSDATE - 2
ORDER BY snap_id;
输出的数据大概是这样的表格形式:
| SNAP_ID | BEGIN_TIME | END_TIME |
|---|---|---|
| 100 | 2024-11-26 08:00 | 2024-11-26 09:00 |
| 101 | 2024-11-26 09:00 | 2024-11-26 10:00 |
| 102 | 2024-11-26 10:00 | 2024-11-26 11:00 |
这个示例是我从 11g 环境摘出来改的,实际不同版本显示会略有差异,但字段含义一致。
如果说客户反馈“上午 10:00 到 10:30 数据库感觉卡”,那么你应该选择快照 101(结束时间 10:00)和快照 103(如果存在 11:00 的快照)。这样起点已经包含了 10:00 到 11:00 的完整状态。原理上你要选择一个刚好跨住问题时间段的起点/终点,不要选问题正中间的短窗口,更不要选死板的整点。
4.3 完整交互生成过程演示
下面我用一个正常场景的交互过程,把每一步贴出来,你照着这个节奏操作基本不会跑偏。
text复制SQL> @?/rdbms/admin/awrrpt.sql
Current Instance
~~~~~~~~~~~~~~~~
DB Id DB Name Inst Num Instance
------- ------------ -------- ------------
1234567890 ORCL 1 orcl
Specify the Report Type
~~~~~~~~~~~~~~~~~~~~~~~
AWR Report Type:
html (生成HTML格式报告)
text (生成纯文本格式报告)
Enter value for report_type: html
Specify the number of days of snapshots to choose from
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enter value for num_days: 2
Listing the last 2 days of Completed Snapshots
...
Instance DB Name Snap Id Snap Started Level
------------ ------------ ---------- ------------------- -----
orcl ORCL 100 26 Nov 2024 08:00 1
orcl ORCL 101 26 Nov 2024 09:00 1
orcl ORCL 102 26 Nov 2024 10:00 1
orcl ORCL 103 26 Nov 2024 11:00 1
Specify the Begin and End Snapshot Ids
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enter value for begin_snap: 100
Enter value for end_snap: 102
Specify the Report Name
~~~~~~~~~~~~~~~~~~~~~~~
Enter value for report_name: /tmp/awr_biz_20241126.html
Using the report name /tmp/awr_biz_20241126.html
...
等脚本跑完,直接查看文件大小和开头内容:
bash复制ls -lh /tmp/awr_biz_20241126.html
head -50 /tmp/awr_biz_20241126.html
能看到正常 HTML 结构,说明已经生成成功。我用 ls -lh 基本能看出文件大小,如果报告只有几十 KB,通常说明快照间数据量不大;如果跑到几十 MB,那就要做好心理建设,打开报告时浏览器可能会卡。
4.4 怎么确认生成结果是否靠谱
报告生成完不是就完事了,最好快速确认报告时间段和业务问题时间匹配。打开 HTML 报告,前几行会显示类似“Snapshot Time: 26 Nov 2024 08:00 - 26 Nov 2024 10:00”的字段。如果起止时间符合预期,那这份报告就具备分析价值;如果发现时间范围不对,立刻回去重新选快照生成,不要拿一份错误数据开始分析,这个习惯能帮你少走很多弯路。
5. 版本差异与参数个性化:一套脚本适配多库环境的经验
工作里最怕的不是不会生成 AWR,而是同一套操作在不同库上跑出来的结果不一样。这里把几个版本相关的问题一次性说清楚。
5.1 11g 到 19c 脚本路径的变化
我在最开始接触 Oracle 11g 的时候,习惯把 awrrpt.sql 的全路径背下来:
text复制/oracle/app/oracle/product/11.2.0/dbhome_1/rdbms/admin/awrrpt.sql
后来切到 12c、19c 环境,发现不同机器 ORACLE_HOME 路径可能完全不同,比如 19c 可能装到 /u01/app/oracle/product/19.0.0/dbhome_1 下。为了不写死路径,我一律用 ? 通配符替代 $ORACLE_HOME:
sql复制@?/rdbms/admin/awrrpt.sql
? 符号是 SQL*Plus 内置的 ORACLE_HOME 环境变量占位符,能自动解析。无论安装在哪个路径下,这条命令都有效,这是最稳妥的写法。
5.2 默认 Top SQL 数量调整
11g 数据库 AWR 报告的 Top SQL 默认采集 30 条(TOPNSQL 参数),但在高峰期如果 TOP 30 没能覆盖到真正有问题的 SQL,你可能需要调大这个数量,否则报告里头部的 SQL 不够看。
调整方式依然是通过包:
sql复制BEGIN
dbms_workload_repository.modify_snapshot_settings(
topnsql => 50
);
END;
/
这里想提醒一下,topnsql 值调大会让 AWR 报告文件变大,生成耗时也会上升,但大多数场景下从 30 调到 50 基本可控。个别业务如果 SQL 重复度极低、TOP 前 80 都没法覆盖问题 SQL,可以临时调整为 80 或 100,但调研完了建议调回来,别让快照采集持续做太多额外工作。
5.3 多套库环境下的保存路径统一规范
我管理的库里,生成 AWR 报告的文件位置我都会刻意保持统一路径,比如统一放到 /u01/awr_backup 目录,然后按日期、库名、快照段三个维度命名:
text复制/u01/awr_backup/ORCL_20241126_100_102.html
这么做的好处是脚本不用反复改,历史报告归档也方便,后面做性能对比时直接按文件名匹配就行。以前有个排查案例,客户说他数据库几天前出现过一次卡顿,让我对比分析下,我直接把对应日期的报告翻出来,命名规范帮了大忙。
6. 读懂 AWR 报告关键模块,快速定位性能瓶颈
有句话说得好:报告生成出来不算本事,能从报告里读出问题才算真功夫。AWR 报告内容非常多,但应急分析时我不建议从头到尾逐段读,效率太低。按照下面这个顺序浏览,基本能在几分钟内锁定初步方向。
6.1 先看 Report Summary 和 Top Timed Events
打开报告后,前面半段位置会有一个“Top 5 Timed Foreground Events”表格,这里通常用加粗等方式显示前几个等待事件的时间占比。可以简单归类:如果 DB CPU 排在第一位且占比很高,说明数据库主要在消耗 CPU 资源,可能存在低效 SQL 的大量逻辑读;如果 db file sequential read 排第一,通常暗示索引扫描相关的物理读比较多;如果看到 enq: TX - row lock contention,那八成是锁等待问题。
某些 AWR 版本里 Top 5 事件会显示为“Top 5 Timed Events”,类型会更细化一些,把后台进程等待也列进去。不太熟练的话优先关注 Foreground Events,因为这是直接影响业务会话的事件。
11g 报告开始部分的示例可能长这样:
text复制Top 5 Timed Foreground Events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Event Waits Time(s) Avg wait (ms) % DB time Wait Class
DB CPU 3,412 43.2
db file sequential read 1,283,456 1,987 1.55 25.2 User I/O
这里“% DB time”是关键判断列,值越大越值得深挖。一个参考经验:如果单个等待事件占比超过 30%,就要特别留意了;如果一个模块占用超过 50%,那基本可以断定问题源头就在这个方向。
6.2 结合 SQL Statistics 模块定位高负载 SQL
“Top SQL by Elapsed Time”部分会罗列出在报告时间段内累计执行时间最长的 SQL。你需要关注的不仅是单次执行时间,还包括执行次数。有些 SQL 单次只要 0.1 秒,但一小时被调用几百万次,累计时间就非常可观。这种 SQL 往往需要结合业务缓存逻辑来看,有时候减少调用次数比优化单次执行更有价值。
拿到 TOP SQL 之后,最直接的手段就是复制 SQL_ID 去 dba_hist_sqltext 里看完整文本,或者去库里查缓存中的执行计划:
sql复制SELECT sql_text
FROM dba_hist_sqltext
WHERE sql_id = '你的SQL_ID';
拿到文本后再结合报告里的执行计划部分去分析是全表扫描还是索引扫描、在哪个环节消耗最高。平时我看报告的习惯是先在 SQL Statistics 里圈出三五个重点 SQL,然后在 Load Profile 里看执行次数趋势,两相对照往往比漫无目的地翻全篇要快得多。
6.3 Segment Statistics 与实例配置的有效性检查
如果 Top SQL 里大量出现全表扫描的 SQL,下一步就去看“Segments by Physical Reads”或“Segments by Logical Reads”这些段统计表。这里会列出读取量最大的数据库对象,可能是表,也可能是索引。看到某个分区表排在最前面,那就说明优化方向大概率要落到这个对象的访问路径上。
实例配置部分里,值得快速浏览的几个指标包括 Buffer Cache Hit Ratio、Library Cache Hit Ratio、Redo 生成量等。Buffer Cache Hit Ratio 并不能单独衡量性能好坏,但如果你发现某个模块命中率极低并且物理读很高,结合等待事件一起判断,还是能给出辅助结论的。
7. 常见报错与处置方案:生成 AWR 报告时踩过的坑
这条路走多了,总会踩坑。下面几个问题都是真实遇到过的,建议先收藏,碰到对应场景时直接对症下药。
7.1 “insufficient privileges”权限不足
用非 DBA 用户执行 awrrpt.sql 时会报类似下面这种错误:
text复制ERROR at line 1:
ORA-00942: table or view does not exist
其实是因为该用户没有访问 dba_hist_snapshot 等数据字典的权限。常规解决方案是使用 sysdba 登录,或者授予用户 SELECT_CATALOG_ROLE:
sql复制GRANT SELECT_CATALOG_ROLE TO your_user;
但需要注意,很多 dba_hist 相关基础表,比如 WRH$ 表,本身权限要求更严格,有时候即便有了 SELECT_CATALOG_ROLE 还是无法查询。所以最省事的方案永远是用 sysdba 生成报告,然后按需将报告分发给对应人员。
7.2 “cannot create AWR snapshot” 或 ORA-13519
手动执行 dbms_workload_repository.create_snapshot() 时,偶尔会遇到类似 ORA-13519 等错误。这个错误通常和快照数据写入异常有关。常见原因有几个:
- SYSAUX 表空间不足,导致 AWR 数据无法写入。
- 快照数据表存在坏块或者处于异常状态。
- 在 RAC 环境中某节点出现资源竞争导致写入失败。
处置优先级是:先确认 SYSAUX 剩余空间,再看告警日志中有无相关 ORA 报错。SYSAUX 空间不足时可以考虑增大数据文件,或者清理历史 AWR 数据,后者一般不做,因为是生产审计数据,务必确认合规后再操作。
7.3 报告里显示的“Snapshot ID 不存在”
有时候你在交互式脚本里输入了两个日期在界面上明明显示的快照 ID,结果回车后提示 snapshot 100 not found。这大概率是因为你选择的起止快照不是同一个数据库实例级别的。在 RAC 多节点环境中,不同节点的快照 ID 不能混用。比如节点 1 的快照 100 对应的时间段,和节点 2 的快照 100 不一定相同,先查视图时注意加实例号过滤:
sql复制SELECT snap_id, instance_number, begin_interval_time, end_interval_time
FROM dba_hist_snapshot
WHERE instance_number = 1
ORDER BY snap_id DESC;
如果你要对比整个数据库层面负载,不要直接拿着节点 1 的起止 ID 去节点 2 生成,先搞清楚需求:单节点问题用单节点报告,全局问题用 RAC 全局报告,别把报告用错场景。
7.4 SYSAUX 表空间持续膨胀
这种情况通常不是一次操作触发的,而是长时间不改 AWR 快照保留参数导致的。我在早期管理一套 11g 系统时,因为没有调保留策略,SYSAUX 从 5GB 涨到快 20GB,最后系统开始报 space 相关告警。
解决方案很直接,就是调整保留策略,把保留窗口从默认 8 天收到 3 天到 5 天(按业务需要),并且适当调大快照间隔到 60 分钟。如果表空间已经占满,那要立刻增加数据文件:
sql复制ALTER TABLESPACE sysaux ADD DATAFILE '+DATA' SIZE 8G AUTOEXTEND ON;
但更重要的事情是回头看 AWR 配置,否则加多少空间都不够用。这套表空间增长逻辑在所有版本里基本一致,只是 ASM 路径写法差异需要注意。
8. 自动化与持续集成:把 AWR 报告生成纳入日常巡检脚本
做到这个层面,已经不属于“偶尔排障拉个报告”的范畴了。如果想对多套库做周期性巡检,手动生成 AWR 报告的方式显然不可持续。这时候需要把整个流程脚本化,甚至纳入统一调度平台。
8.1 一个现成的 Shell 封装脚本思路
我平时会在 Linux 环境写一个极简脚本,思路是:通过环境变量指定要连接的数据库实例,然后查最近的快照,自动选择倒数第二个和倒数第一个快照(最近的完整窗口),生成 HTML 报告并归档到指定目录。
脚本核心命令段如下所示:
bash复制#!/bin/bash
export ORACLE_SID=ORCL
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0
SET FEEDBACK OFF
SPOOL /tmp/snap_list.txt
SELECT MIN(snap_id) || ',' || MAX(snap_id)
FROM (
SELECT snap_id
FROM (
SELECT snap_id, ROW_NUMBER() OVER (ORDER BY snap_id DESC) rn
FROM dba_hist_snapshot
)
WHERE rn <= 2
);
SPOOL OFF;
EOF
然后读取 /tmp/snap_list.txt 里的起止快照 ID,再调用 awrrpt 生成报告。这样做的前提是脚本跑之前已经有至少两个快照存在,否则要单独处理。有的版本环境下 SPOOL 会带出额外空格,你需要用 sed 或 awk 清洗一下,细节不少但不复杂。
8.2 使用 dbms_scheduler 定时输出 AWR
如果不想依赖操作系统定时任务,还可以考虑写在数据库内部,用 Scheduler Job 定时生成报告。一套基础做法是写一个 PL/SQL 匿名块,调用 dbms_workload_repository.awr_report_html,将 CLOB 写入一张自定义表,然后再定期导出这一张表的数据。这个方法在银行、证券客户里常见,是因为他们出于合规需要,要求保留每日 AWR 报告,用于后续问题追溯。
8.3 批量巡检多库时的命名规范
手上库比较多的时候,建议把每个数据库的 DBID 都加进脚本参数。因为 AWR 数据是按 DBID 隔离的,如果不加 DBID,有可能连错实例生成了完全无关的报告,浪费几分钟是小,分析错方向才是大事。
我个人的脚本约定是把目标库的 DBID、实例号、起始快照、结束快照都作为参数传入,后台跑完同时生成四类报告:整体、CPU、等待事件、TOP SQL。这样日报生成后,一眼就能看出当天数据库的健康趋势,也方便后续汇总。
9. 从“能出报告”到“会利用报告”:我的几条实战体会
文章写到这,相当于把快速生成 AWR 报告的技能树从上到下梳理了一遍。但对于刚入门的读者,我想再补充几条实战层面的体会,方便你把这些知识真正用起来。
第一,不要只生成报告却不核对时间窗口。这事我栽过一次跟头:帮客户分析生产问题,随手选了最近两个快照,生成出来的报告跟业务高峰期完全不沾边,白白浪费了排查时间。现在我在生成前一定会把 begin_interval_time 打印出来看一眼,养成习惯后很少再犯这类错误。
第二,把“生成报告”和“定位问题”当成两件事。生成报告可以提速,但定位问题不能仓促。AWR 报告里包含的信息维度非常多,如果你用 10 秒生成报告,那至少留 10 分钟读报告。首先看负载概况,再对比基线,最后才针对异常模块深挖 SQL。这个过程有经验积累的成分,不必急于求成。
第三,注意长期留存与口径统一。有些客户要求把 AWR 保留一年甚至更久,这时候单靠数据库里的 dba_hist_snapshot 自动保留是远远不够的,更合理的思路是把报告导出成文件备份到独立的存储或对象存储中,并且统一命名前缀,这样溯源的时候效率很高。
这套操作吃透以后,不管是自己维护实验环境,还是到客户现场处理生产问题,至少生成报告这个环节你不会再成为瓶颈。剩下的,就是拿到报告之后怎么高效解读的问题了,那是另一个值得写一整篇分享的话题。下次有空,我再把如何从 Top Event 和 SQL Order 反推具体优化手段的完整分析流程整理出来,咱们接着聊。
