简介:这份PDF由黄伟波撰写,主题为Oracle数据库AWR报告分析,是面向数据库管理员、性能优化工程师及初学者的实用指南。内容从AWR基本概念讲起,涵盖统计信息分类、STATISTICS_LEVEL参数、报告核心组成与维护进程;AWR作为自动工作负载仓库,负责收集系统级、会话级与对象级统计信息,并通过快照保留历史数据,便于时段对比和趋势分析。同时介绍通过企业管理器和命令行生成报告、制作基线报告与时段对比报告。分析方面聚焦缓冲区缓存命中率、硬解析次数、逻辑读取等关键指标,帮助定位SQL性能瓶颈与系统资源消耗。资源为1个PDF文件,压缩包约7.13MB,全文目录清晰,适合离线阅读。已有226人浏览学习。对于希望掌握从导出到分析完整流程、快速提升数据库调优能力的读者,这份材料能提供成体系的方法参考。
1. 从一份报告到一次体检:Oracle 数据库 AWR 报告分析到底在解决什么问题
数据库响应变慢的时候,DBA 的第一反应通常是生成一份 AWR 报告。报告里几十页指标,真正能指导调优决策的其实就那么十几个数字。这份《Oracle 数据库 AWR 报告分析》资料,做的就是把这些数字按分析优先级排好,讲清楚怎么读、先看什么、哪些数字会骗人。它来自一线 DBA 的实操总结,不是照着官方文档抄概念。
资料适合三类人:刚接手 Oracle 运维的工程师,需要一套能照着走完的报告解读流程;开发 DBA,想把等待事件和 SQL 性能快速对上号;还有被业务反复追问"为什么慢了"的值班人员。它解决的不是某个参数怎么调,而是 AWR 分析的完整方法论——从生成报告、读指标到避坑判断,一套闭环。
我按这份资料的分析思路重新梳理了自己的实操流程,包括报告生成、关键指标阅读、常见误判和日常巡检清单。下面这些内容大多来自真实排查场景,新手可以跟步骤走,老手也能对照检查自己的分析习惯有没有漏项。
2. 读懂 AWR 报告结构与关键指标:先定位瓶颈再动手调优
AWR 报告的目录结构相对固定,读得快不快,取决于你对每一段在讲什么、位置在哪里有没有形成肌肉记忆。资料在这部分花了不少篇幅讲阅读顺序,我结合自己的使用习惯,把它压缩成三个动作:确认快照前提、看全局繁忙度、落到等待事件和 SQL。顺序反了,很容易被某一段异常数字带偏方向。
2.1 报告页签与快照区间:读报告前先确认前提
很多新手拿到报告第一件事就是翻到 Top 10 Foreground Events 那一页,这是最常见的错误开场。分析之前必须先确认两个前提:报告覆盖的时间区间是否可信,以及这个区间内数据库是否真的在忙。前提错了,后面所有百分比判断都会失去意义。
第一步是看报告头部的 Report Summary。里面会列出起始快照 ID、结束快照 ID、每个快照对应的具体时间,以及 Elapsed Time 和 DB Time 两个关键数字。常见做法是先把这两个数字记下来:Elapsed Time 是报告的物理时间跨度,DB Time 是所有会话在数据库里累计消耗的时间。如果 Elapsed 是 60 分钟而 DB Time 只有 20 分钟,平均活跃会话数就是 0.33 左右,整体负载偏低,这时候深挖某条 SQL 的意义不大,更值得关注的是业务是否真的在上量。
第二步是核对快照区间是否连续。生产库的快照间隔默认是 60 分钟,但很多人不知道dbms_workload_repository.modify_snapshot_settings可以把间隔改成 15 分钟或 30 分钟。如果报告里的 Elapsed Time 和两个快照的实际时间差对不上,常见原因是数据库在区间内重启过,或者有人手工删过快照。这时候 Load Profile 里所有"每秒"类指标都会被稀释或放大,百分比类指标也会失真。
我的习惯是把快照检查做成一排固定动作:先看快照 ID 是否连续,再看 begin_interval_time 和 end_interval_time 的差值,最后确认当前数据库的快照间隔配置。资料里把这一步叫作"分析前的前置检查",它救过的分析不止一次——有次我拿着一份 Elapsed 显示 0 分钟的报告查了半天,后来才发现是快照区间跨了一次重启,那期间数据库其实根本没在服务。
提示:分析前如果发现 Elapsed 与快照间隔不一致,先解决快照问题再继续,不要带着失真数据往下读。
2.2 关键指标优先级:DB Time、Top Events 与 Load Profile
报告页签虽然多,真正决定分析方向的其实只有三块。第一块是 Report Summary 里的 DB Time 与 Elapsed Time 的比值,这是系统繁忙度的总开关。第二块是 Top 10 Foreground Events,它告诉你数据库时间花在了哪个内核等待事件上。第三块是 Load Profile,它给出每秒级别的 Redo、逻辑读、硬解析、执行次数等吞吐指标,用来判断负载形态到底是查询型、写入型还是解析型。
我一般按资料里的顺序读:先看 DB Time / Elapsed,大于 1 说明系统存在并发排队,小于 0.3 说明系统相对空闲。这里有个容易犯的错误——看到 DB Time 高就直接开调 SQL。DB Time 高只是结果,原因可能在锁、在 IO、在 CPU 排队,要结合 Top Events 看。测试环境里我见过很多 DB Time 虚高的情况,其实是 AWR 报告覆盖了夜间批量任务,白天正常业务根本没受影响。
Top 10 Foreground Events 的表格有四个列值得逐列读:Waits 表示等待次数,Timeouts 表示超时次数,Avg Wait 是平均每次等待的耗时,最右边那列 % DB time 才是判断该事件是否值得分析的核心依据。资料里特别强调过一个反直觉的点:等待次数多不代表问题大。比如 log file sync 在 OLTP 系统里可能每分钟发生上千次,但每次只有 0.1 毫秒,% DB time 才 3%,这时候去调 redo 写入路径就是白费力气;反过来,db file sequential read 次数不多,但 % DB time 占 40%,那才是真正要动手的方向。
Load Profile 这段指标密度很高,但关键的只有四个:Redo size 反映写入量,Logical reads 反映查询量,Hard parses 反映硬解析压力,Executes 反映整体执行频率。硬解析与执行次数的比值如果长期超过 10%,基本可以断定应用层没有合理使用绑定变量。资料给出的路径是"先看 Load Profile 找异常方向,再做 SQL 层定位",这个顺序很重要——直接从 Top SQL 开始看,容易漏掉那些单次不慢但反复执行的短事务 SQL,这类 SQL 在 Top SQL 里往往排不上号,却可能是硬解析和锁等待的源头。
2.3 等待事件与瓶颈类型的映射关系
等待事件是 AWR 报告里信息密度最高的一段,对新手也最不友好。资料里实际上用一张隐式对应表把常见事件和瓶颈类型做了归类,我把它展开成下面的表格,排查的时候直接对照:
| 等待事件 | 常见瓶颈 | 优先排查方向 |
|---|---|---|
| DB CPU | CPU 计算资源不足或 SQL 逻辑读过大 | Top SQL 的 buffer gets、执行计划 |
| db file sequential read | 单块读 IO 延迟高或索引访问过度 | 索引扫描路径、磁盘延迟分布 |
| db file scattered read | 全表扫描或并行 IO 吞吐不足 | 大表是否缺索引、是否该走并行 |
| log file sync | 提交过于频繁或 redo 写盘慢 | 应用 commit 频率、redo 日志大小 |
| log file parallel write | redo 写盘吞吐瓶颈 | 存储层 IO 能力、redo 文件分布 |
| SQL*Net more data to client | 应用端读数据慢或网络延迟 | 应用 fetch 大小、网络链路 |
| enq: TX - row lock contention | 行锁竞争 | 未提交事务、批量 update 冲突窗口 |
| enq: TX - index contention | 索引根块或分支块竞争 | 索引反向键、随机主键插入 |
| gc cr block busy | RAC 跨节点一致读竞争 | 热点块分布、应用亲和性 |
| read by other session | 同一数据块被多会话争抢 | 热点对象、缓存大小 |
表格只是分析的入口,真正判断时还要结合事件旁边的 Avg Wait 和 % DB time。我印象最深的是资料里举的 log file sync 例子:某个系统的等待次数多到吓人,但平均等待只有一两毫秒,% DB time 不到 5%,最终确认的问题是应用在循环里逐条 commit,调优动作是改成批量提交,存储根本没换。反过来,如果 log file sync 的 Avg Wait 涨到几十毫秒,那就要查 redo 日志所在的磁盘是不是和其他业务混用,或者 redo log 文件尺寸偏小导致切换频繁。
读等待事件时还要养成一个习惯:把 Top 5 事件的 % DB time 加起来看。如果前五个事件的占比合计达到 80% 以上,说明瓶颈非常集中;如果加起来才 40%,说明负载分散在很多事件上,这时候单靠等待事件下结论很容易翻车,要结合 Segment Statistics 和 SQL ordered by Waits 继续缩小范围。资料里有句话我一直记着:"等待事件告诉你时间去哪了,但不告诉你为什么去那。"
3. 手工生成与对比 AWR 报告:awrrpt.sql 和 awrddrpt.sql 的实操闭环
读报告的能力再强,也得先把报告准确生成出来。Oracle 自带的awrrpt.sql和awrddrpt.sql是标准的报告生成入口,资料里把交互流程、格式选择和常见报错都讲了一遍。这两个脚本用起来不难,难的是把每个交互参数的含义搞清楚,以及把生成报告这个动作固化到日常巡检里。
3.1 生成单份 AWR 报告的完整步骤与参数
生成单份报告的入口是awrrpt.sql,文件位于$ORACLE_HOME/rdbms/admin/目录下,任意能连到数据库的会话都可以调用,一般用 sysdba 身份执行:
sqlplus / as sysdba SQL> @$ORACLE_HOME/rdbms/admin/awrrpt.sql执行后脚本会依次询问五个变量:报告类型、最近几天、起始快照 ID、结束快照 ID、输出文件名。下面这张表是我整理的参数说明,照着填基本不会出错:
| 交互变量 | 可选值 | 说明 |
|---|---|---|
| report_type | text / html | 文本格式方便 grep 检索,HTML 适合浏览器查看 |
| num_days | 正整数 | 限定本次生成快照的搜索范围,按天往回数 |
| begin_snap | 快照 ID | 起始快照,必须是 dba_hist_snapshot 里的合法 ID |
| end_snap | 快照 ID | 结束快照,必须大于 begin_snap |
| report_name | 自定义文件名 | 不输的话会生成 awrrpt_1_xxx 之类的默认名 |
生产环境我基本只用文本格式,原因很实际:文本报告可以用 grep 和 sed 做批量检索,方便把十几份报告放在一起对比,资料里的示例也以文本报告为主。HTML 格式适合给业务方看,但生成后不方便二次处理。
生成之前建议先确认可用的快照范围,这一步直接决定你选哪个 begin_snap 和 end_snap。查询方式是从数据字典里取最近几天的快照:
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;这条 SQL 的结果里每个 snap_id 对应一个时间点。选快照时至少要跨两个 ID,因为 AWR 报告的本质是两个快照之间的增量统计,同一个快照没法计算任何"每秒"指标。如果你想精确分析某个变更窗口,可以先用exec dbms_workload_repository.create_snapshot;手工打一个快照,完成变更后再打一个,这样报告区间就能完全覆盖变更前后。
交互式生成在自动化场景里不太好用,常见做法是用管道把参数按顺序喂给脚本。下面这条命令等价于手动输入 text、1、最近两个快照的 ID 和输出文件名:
echo -e "text\n1\n120\n121\nawr_20250331.txt" | \ sqlplus -s / as sysdba @$ORACLE_HOME/rdbms/admin/awrrpt.sql这里\n分隔的五个值依次是格式、最近天数、起始快照、结束快照和文件名。注意如果传入的 begin_snap 和 end_snap 差值过大,报告会变得很长,加载和阅读都费劲;我一般控制在 2 到 4 个快照之间,既能看出趋势又不至于信息过载。
提示:awrrpt.sql 里的 num_days 只是限定快照搜索范围,不是报告时长。报告时长完全由 begin_snap 和 end_snap 决定。
3.2 生成 AWR 对比报告:找趋势比找绝对值更有用
单份报告反映的只是一个时间切片的状态。要回答"从哪天开始变慢的""上周和这周差在哪",必须用对比报告。对比报告的入口是awrddrpt.sql,用法和awrrpt.sql几乎一样,但会要求你分别选择两个时间段:一个作为基线区间,一个作为对比区间。
echo -e "html\n1\n110\n115\n200\n205\nawr_diff_0331.html" | \ sqlplus -s / as sysdba @$ORACLE_HOME/rdbms/admin/awrddrpt.sql这段输入的含义是:报告格式 HTML,最近 1 天范围内,基线区间取快照 110 到 115,对比区间取快照 200 到 205,输出文件名是awr_diff_0331.html。对比报告会把两组快照的 Load Profile、Top Events、SQL 统计并排列出,差异列直接显示百分比变化,找拐点比单份报告快得多。
使用对比报告时有一个关键前提:两段快照的时间跨度必须接近。比如基线区间覆盖 60 分钟,对比区间覆盖 120 分钟,那所有换算成每秒的指标都不具备可比性,% DB time 也可能因为区间长度不同产生偏差。资料里有个实际案例:某系统凌晨批量任务从 4 点调整到 3 点,单份报告看哪一段都正常,对比报告里才发现硬解析涨了 70%,顺着查下去是批量任务启动时没有绑定变量。这类"趋势类"问题,单份报告永远看不出来,这也是为什么我会建议把对比报告纳入每周固定巡检。
3.3 一份可复用的小脚本:批量生成并归档报告
手工执行交互脚本适合临时排查,但日常巡检需要的是可重复的动作。我一般会把生成和归档合在一个 Shell 脚本里,每周跑一次,历史报告留档供回溯。下面是一个简化但完整的版本:
#!/bin/bash # 用法: ./gen_awr.sh <ORACLE_SID> [最近天数] export ORACLE_SID="${1:-orcl}" export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1 export PATH="$ORACLE_HOME/bin:$PATH" DAYS="${2:-1}" DT=$(date +%Y%m%d_%H%M) OUT_DIR=/u01/awr_archive WORK_DIR=/home/oracle/awr_work mkdir -p "$OUT_DIR" "$WORK_DIR" cd "$WORK_DIR" # 取最近时间段内的最后两个快照 ID SNAPS=$(sqlplus -s / as sysdba <<EOF set pagesize 0 linesize 200 feedback off SELECT min(snap_id) || ' ' || max(snap_id) FROM ( SELECT snap_id FROM dba_hist_snapshot WHERE begin_interval_time > sysdate - $DAYS ORDER BY snap_id DESC ) WHERE ROWNUM <= 2; EOF ) BEG=$(echo "$SNAPS" | awk '{print $1}') END=$(echo "$SNAPS" | awk '{print $2}') echo "使用快照: $BEG -> $END" echo -e "text\n$DAYS\n$BEG\n$END\nawr_${DT}.txt" | \ sqlplus -s / as sysdba @$ORACLE_HOME/rdbms/admin/awrrpt.sql > /dev/null mv awr_${DT}.txt "$OUT_DIR/awr_${DT}.txt" find "$OUT_DIR" -name 'awr_*.txt' -mtime +90 -delete echo "报告已归档: $OUT_DIR/awr_${DT}.txt"脚本里的几个关键点说明一下:内层子查询先按时间倒序取最近的两个快照 ID,再用 min 和 max 把它们转成正确的区间顺序,避免出现开始大于结束的情况;echo -e配合\n把五个交互参数一次性喂给 awrrpt.sql;最后用find -mtime +90清理三个月前的旧报告,防止归档目录无限膨胀。实际部署时把 ORACLE_HOME 和 OUT_DIR 换成你自己的路径,再用 crontab 每周执行一次即可。
这个脚本能保证每次生成的都是同一个时间粒度、同一个最近天数的报告,消除手工操作带来的参数漂移。资料里把它归类到"巡检自动化"的范畴,我自己的体会是:报告生成如果依赖人工一步步确认,时间一长必然会漏跑,而漏跑的那一周往往正是需要回溯故障的一周。
4. AWR 分析实战避坑:五个最容易翻车的判断
这一章的内容既来自资料里的案例分析,也来自我自己这些年踩过的坑。AWR 分析里最难的从来不是生成报告,而是别被表面数字牵着走。每一条我都按"现象、原因、解决"拆开,希望能帮你省掉一些不必要的加班。
4.1 现象:DB Time 高,Top 10 Foreground Events 却像"没事发生"
现象:某次分析一个连接数很高的业务库,DB Time 与 Elapsed 的比值超过 2,系统忙得厉害,但 Top 10 Foreground Events 里排第一的竟然是SQL*Net message from client,看起来像是"客户端没发请求",和系统繁忙完全对不上。
原因:这个事件本质是空闲等待,AWR 的 Foreground Events 统计会把它的累计等待时间算进去。连接数越多、客户端在思考的空闲占比越高,这个事件的累计时间就越长,甚至压过真正的性能等待事件。只看事件名,就会得出"系统在等客户端"的错误结论。
解决:读 Top Events 前先区分空闲事件和非空闲事件。AWR 文本报告的 Wait Events 段里有 idle 分类,HTML 报告也有对应的树状结构。判断时只统计非空闲事件和 DB CPU 的 % DB time,不要被 Waits 次数带偏。资料里的原话是"不要被事件名字吓到,要看它后面那个百分比",这句话后来成了我每次分析都会默念的判断准则。
4.2 现象:单条 SQL 执行计划变了,系统整体变慢
现象:某系统连续几份 AWR 报告里,SQL ordered by Elapsed Time 第一名都是同一条查询,单次执行时间从 50 毫秒涨到 8 秒,但表的数据量并没有明显增长。单份报告看,问题就是这条 SQL 慢;对比报告才发现,慢是从某个快照区间开始的,之前同一 SQL 的执行计划 hash value 在 480 附近,之后变成了 720 多。
原因:统计信息自动收集任务在凌晨刷新了相关表的统计,优化器基于新统计选择了全表扫描。这类问题的排查顺序是:在 SQL ordered by Elapsed Time 里锁定额外的 SQL,然后从dba_hist_sql_plan里对比两个快照间的计划变化。判断标准很直接——如果 SQL 执行次数没变,而单次逻辑读翻倍甚至更多,基本就是执行计划变了。
解决:短期用 SQL Plan Management 把稳定计划设为基线并固定,配置dbms_sqldiag.accept_sql_plan_baseline等操作;长期调整自动统计信息收集策略,把大表的收集时间挪到业务低谷,并对敏感对象锁定统计信息。资料里特别提醒,遇到这类问题别急着加并行度或改索引,先确认是不是计划漂移,否则会在错误的方向上反复试。
4.3 现象:Elapsed Time 与快照间隔对不上
现象:生成的报告头部显示 Elapsed Time 是 0 分钟,或只有几分钟,但两个快照的实际间隔应该是一小时。第一次遇到时我以为是脚本选错了快照,重新生成两遍结果都一样。
原因:快照区间内数据库发生过重启。实例重启后,内存中的数据全部清空,AWR 只能基于磁盘上已有的快照计算,重启前的负载数据和重启后的负载数据被硬压进同一个区间,导致所有增量指标失真。另一个常见诱因是有人手动删过中间的 AWR 快照,破坏了快照连续性。
解决:回到dba_hist_snapshot确认快照是否连续,同时查实例启动时间。如果确认跨了重启,分析时要主动把重启前后拆成两段,分别生成报告。资料里把这个坑排在很靠前的位置,因为它影响的是报告里所有百分比类指标的可信度——我后来形成习惯,拿到报告第一件事就是看 Elapsed 和快照时间差是否一致,不一致就先解决快照问题再继续。
4.4 现象:内存命中率很高,但硬解析暴增
现象:有回分析一个 OLTP 库,Buffer Cache 命中率 99.8%,Shared Pool 也没有告警,怎么看内存都健康。但 Load Profile 里 Hard parses 高达每秒 200 多次,而 Executes 只有 400 左右,几乎一半的 SQL 都在重新解析。
原因:应用层在拼接 SQL 字符串,导致每次执行的 SQL 文本都不一样,共享池里存不住可复用的游标。内存充足只是表象,因为 SQL 文本不同,命中率指标再好也没用。解析行为异常才是真正的瓶颈信号。
解决:解决方向有三个:推动应用改造使用绑定变量,这是根治方案;对存量系统临时把cursor_sharing设为FORCE,这是后悔药,能缓解但不能长期依赖;对高频解析语句做匹配规则,或使用 SPM 固定执行计划。资料里把这种情况总结成一个反直觉的道理:加内存治不了硬解析。Shared Pool 开得再大,存不下不断变化的 SQL 文本,照样每秒几百次解析。我后来听到"内存充足"四个字都会多问一句:够不够不是看命中率,而是看解析行为。
4.5 现象:ADDM 结论和人工分析结论打架
现象:AWR 报告里自带 ADDM 分析,多数时候它的结论是靠谱的,但也有和人工逐项排查对不上的时候。最常见的是 ADDM 说 IO 等待占比最高,而人工看 Top 10 Foreground Events 里排第一的是 DB CPU。
原因:ADDM 的统计窗口和 AWR 报告的快照窗口存在偏差。ADDM 是基于平均活跃会话的归因模型,AWR 是基于会话累计时间的事件统计,两者对"谁占主导"的定义不同,自然会算出不同的结论。另外,ADDM 分析的是它自己选择的基线区间,未必和人工选的快照区间完全重合。
解决:把 ADDM 和 AWR 当作交叉验证工具,而不是互斥的答案。先按 ADDM 的提示圈定一个范围,再回到 AWR 的等待事件和 SQL 统计里确认细节。资料里给的行动准则是"ADDM 看方向,AWR 看细节,SQL 看实锤"。我在实际分析中遇到两者冲突时,会先重新核对快照区间,因为在多数情况下,冲突的根源是区间没有对齐,而不是工具本身谁对谁错。
5. 把 AWR 分析固化到日常巡检:一份可抄的检查清单与归档习惯
最后落一个每天都能用的东西。我从资料里整理了一份精简版检查清单,每次分析前按顺序过一遍,能覆盖大多数性能问题的第一轮定位:
| 检查项 | 看什么 | 异常判断 |
|---|---|---|
| 快照区间 | Elapsed 与快照时间差 | 不一致先处理快照问题 |
| 繁忙度 | DB Time / Elapsed | 比值大于 1 才深入分析 |
| 事件分布 | Top 10 Foreground Events | 非空闲事件占比高才判瓶颈 |
| 负载形态 | Load Profile 的 Redo 与逻辑读 | 与基线对比找异常增量 |
| SQL 贡献 | SQL ordered by Elapsed Time | 前五条占比超 60% 重点查计划 |
| 解析行为 | Hard parses 与 Executes 比值 | 大于 10% 检查绑定变量 |
除了清单,我还养成了一个归档习惯:每周固定导一次文本格式的 AWR 报告,按库名和时间戳存到独立目录。遇到问题需要回溯时,用一条 grep 就能在历史报告里定位等待事件的占比变化:
grep -A 6 "Top 10 Foreground Events" /u01/awr_archive/awr_*.txt | head -60这个习惯在实战里救过我一次。某系统每隔两周就出现一次晚高峰抖动,单次报告看不出任何规律。翻出连续十周的归档报告一对比,才发现每周三晚的某个定时任务都在同一时段拉高log file sync的占比,而那段时间恰好是业务批量提交的高峰。没有历史归档,这个规律恐怕要靠玄学才能猜出来。
从那以后,我每次分析 AWR 都强制自己先跑一遍快照区间确认,再按清单逐项过,最后才打开 Top SQL。这套动作现在已经是肌肉记忆,也让我少走了很多弯路。希望这份分析思路和避坑清单帮到你,下次拿到报告时能少一点"不知道从哪看起"的犹豫。
本文还有配套的精品资源,点击获取