☰
Oracle AWR 报告分析实战:从 DB Time 到 Top 5 等待事件的调优链路
2026/10/2 8:42:09 网站建设 项目流程

简介:这份PDF文档面向Oracle数据库管理员与运维工程师,系统讲解AWR(Automatic Workload Repository)报告的解读方法,帮助读者从快照数据中定位数据库性能瓶颈、优化配置。内容围绕WORKLOAD REPOSITORY report展开,涵盖DB Name、Snap Id、Elapsed与DB Time等关键字段含义,并通过Report A与Report B的对比实例,演示如何用DB Time与CPU时间比值判断系统负载,还涉及AIX环境下bindprocessor查看处理器、Buffer Cache与Shared Pool等SGA区域大小分析,以及Load Profile中Redo size、Logical reads、Hard parses等指标的判读要点,并强调选择代表性分析时间段的重要性。资源包为1个PDF文件,大小约1.18MB,结构紧凑便于随时查阅。目前已有580人学习下载,适合希望掌握AWR报告分析思路、提升数据库调优能力的读者参考。

1. 拿到 AWR 报告先别翻 Top SQL:从 DB Time 和 Elapsed 的比值读出系统真实压力

很多人拿到一份 AWR 报告,第一反应是直接跳到「SQL ordered by Elapsed Time」找最慢的语句,然后开始加索引、改 SQL。这个顺序大概率是错的。AWR 是 Oracle 10g 引入的自动负载信息库(Automatic Workload Repository),它靠对比两次快照之间的统计差值生成报表,本质是一份「时间都花在哪了」的账单。账单没看懂就动手,等于闭着眼睛调优。

这份《OracleAWR报告详细分析.pdf》的价值在于,它没有停在指标定义层面,而是把 Load Profile、Instance Efficiency、Top 5 Timed Events、RAC Statistics、Wait Events 这几大块串成了一条从「判断系统忙不忙」到「定位具体等待」的链路。它适合两类人:一是刚接手 Oracle 运维、需要照着报告逐项读的 DBA;二是遇到性能告警、想快速判断是数据库问题还是应用问题的后端工程师。核心判断逻辑其实就一句话——先看 DB Time 和 Elapsed 的比值,再决定要不要往下深挖。

2. 读懂负载概况:DB Time、Elapsed 与 CPU 核数的三角关系

2.1 DB Time 到底统计了什么

DB Time 是 AWR 里最容易被误读的指标。它的定义是:所有非后台进程在数据库运算和等待(不含空闲等待)上花费的总时间,公式为 DB Time = CPU Time + 非空闲 Wait Time。注意两个限定词——「非后台进程」和「非空闲等待」。这意味着 DB Time 不包含 Oracle 后台进程(如 DBWR、LGWR、PMON)消耗的时间,也不包含像sql*net message from client这类空闲等待。

文档里给了一个很直观的例子:79 分钟内收集了 3 次快照,DB Time 只有 11 分钟,而系统有 8 个逻辑 CPU。平均每个 CPU 耗时 11/8 ≈ 1.4 分钟,CPU 利用率约 1.4/79 ≈ 2%。这个数字说明系统压力非常小,根本不需要调优。反过来,如果 DB Time 接近甚至超过 Elapsed × CPU 核数,说明数据库已经把 CPU 吃满了,这时候才需要认真看后面的等待事件。

2.2 用 Report A 和 Report B 做对比判断负载

文档里用两份报告做了对比,这个对比方法值得直接抄下来用:

报告Elapsed (mins)DB Time (mins)CPU 核数DB Time / (Elapsed × 核数)结论
Report A59.51466.378466.37 / (59.51×8) ≈ 98%CPU 几乎被 Oracle 占满
Report B59.6319.49819.49 / (59.63×8) ≈ 4%平均负载很低

Report A 里,60 分钟窗口内 8 个核总共提供 480 分钟的 CPU 时间,DB Time 466.37 分钟意味着 CPU 有 98% 的时间在处理 Oracle 的非空闲操作。Report B 只有 4%,说明服务器大部分时间在闲着。

这里有个关键提醒:对于批量系统,数据库负载往往集中在某个时间段。如果快照周期没覆盖到那段高峰,或者跨度太长把大量空闲时间也包进来了,算出来的比值会严重偏低,分析结论就是废的。所以选分析时间段时,一定要选能代表性能问题的那段窗口,而不是随便挑一个整点。

提示:DB Time 远小于 Elapsed 不代表没问题,只代表「平均下来不忙」。如果业务方反馈某个时刻卡顿,你需要把快照粒度调细,或者直接查那个时间段的 ASH 数据。

2.3 从 Cache Sizes 和 Load Profile 看资源分配

Cache Sizes 部分显示 SGA 各区域大小,包括 Buffer Cache、Shared Pool Size、Log Buffer 和 Std Block Size。文档特别指出,Shared Pool 里的 library cache 和 dictionary cache 发生 cache miss 的代价远高于 buffer cache,所以 Shared Pool 的设置要确保最近使用的数据都能被缓存。这个判断在后续 Instance Efficiency 的 Library Hit 指标里会得到验证。

Load Profile 部分按 Per Second 和 Per Transaction 两个维度列出负载指标。文档给了一组阈值参考:Logons 大于每秒 1~2 个、Hard Parses 大于每秒 100、全部 Parses 超过每秒 300,就可能有争用问题。Redo size 反映数据变更频率,Logical reads 反映逻辑读压力,Block changes 反映修改频率。这些值单独看没有「正确」答案,必须和基线对比才有意义。

3. 实例效率与等待事件:从命中率到 Top 5 的排查路径

3.1 Instance Efficiency 里的关键命中率怎么读

Instance Efficiency Percentages 这一节列了一堆百分比,文档明确说「没有所谓正确的值」,只能根据应用特点判断。但有几个阈值是业界共识,可以直接拿来用:

指标理想值低于阈值时的动作
Buffer Nowait %> 99%存在缓冲区争用,查等待事件确认
Buffer Hit %OLTP > 95%,低于 80% 考虑加内存检查 top physical reads SQL
Library Hit %> 95%考虑加大 Shared Pool、使用绑定变量
Latch Hit %> 99%检查 Shared Pool latch 争用,可能需绑定变量或调大 Shared Pool
In-memory Sort %> 95%调大 PGA_AGGREGATE_TARGET 或 SORT_AREA_SIZE
Soft Parse %> 95%低于 80% 说明 SQL 基本没复用,需绑定变量

文档里有个反直觉的点值得注意:Buffer Hit 高不一定代表系统好。比如大量非选择性索引被频繁访问,会造成命中率很高的假象,实际伴随大量db file sequential read。真正要警惕的是命中率的突变——突然增大就查 top buffer get SQL,突然减小就查 top physical reads SQL。

3.2 用 Top 5 Timed Events 确定下一步方向

Top 5 Timed Events 是报告概要的最后一节,按等待时间占比倒序列出最严重的 5 个等待。文档给了一个非常实用的排查路径:

  • 如果buffer busy wait严重 → 继续看 Buffer Wait 和 File/Tablespace IO 区,识别哪些文件导致问题
  • 如果 I/O 事件严重 → 看按物理读排序的 SQL,识别哪些语句在大量 I/O
  • 如果 LATCH 等待高 → 看详细 LATCH 统计,识别具体是哪个 latch

一个性能良好的系统,CPU time 应该排在 Top 5 的前面。文档里那个例子,CPU time 排第一,但log file parallel write占了 7%,说明日志写入有一定压力。如果 CPU time 不在前面,说明系统大部分时间在等待,这时候就要顺着等待事件往下挖。

3.3 常见等待事件的定位与处理

文档对几个高频等待事件给了详细说明,这里整理成可操作的排查步骤:

db file scattered read(文件分散读取):通常与全表扫描或 fast full index scan 有关。排查时结合v$session_longops看长时间运行的操作,确认全表扫描是否必要。如果希望某条语句走索引,可以调整optimizer_index_cost_adj,默认 100,理解为 FULL SCAN COST / INDEX SCAN COST。

db file sequential read(文件顺序读取):单块读等待,通常因表连接顺序糟糕或使用了非选择性索引。检查索引扫描是否必须,确认多表连接的驱动行源是否正确。

buffer busy wait(缓冲区忙):这个值不应大于 1%。排查时先查v$event_name确认参数含义——9i 的 p3 是 id,10g 的 p3 是 class#。然后按等待位置分类处理:

-- 获取产生 buffer busy waits 的 SQL 语句 select sql_text from v$sql t1, v$session t2, v$session_wait t3 where t1.address = t2.sql_address and t1.hash_value = t2.sql_hash_value and t2.sid = t3.sid and t3.event = 'buffer busy waits'; -- 获取等待块的类型和所在 segment select 'Segment Header' class, a.segment_type, a.segment_name, a.partition_name from dba_segments a, v$session_wait b where a.header_file = b.p1 and a.header_block = b.p2 and b.event = 'buffer busy waits' union select 'Freelist Groups' class, a.segment_type, a.segment_name, a.partition_name from dba_segments a, v$session_wait b where a.header_file = b.p1 and b.p2 between a.header_block + 1 and (a.header_block + a.freelist_groups) and a.freelist_groups > 1 and b.event = 'buffer busy waits';

第一段查询把等待事件和当前会话、SQL 文本关联起来,定位到具体语句。第二段查询通过 p1(文件号)和 p2(块号)反查 segment,判断等待发生在段头、freelist 组还是数据块。参数 p1、p2、p3 的含义在不同版本有差异,9i 的 p3 是等待原因编号,10g 变成了块类型编号,这个版本差异是排查时最容易翻车的地方。

如果等待在段头,说明 freelist 块太少,可以增加 freelist 或 freelist groups;如果在 undo header,增加回滚段;如果在 undo block,增加提交频率;如果在 data block,说明有热块,可以增大 PCTFREE、减小块大小、优化 SQL 或增加 INITRANS(通常设 5 就够,每个 ITL 槽占 24 字节)。

4. 避坑与常见问题:AWR 分析里最容易翻车的五个地方

4.1 快照窗口选错,分析结论全废

现象:报告显示系统很空闲,但业务方持续反馈卡顿。

原因:批量系统的负载集中在特定时段,如果快照周期没覆盖高峰,或者跨度太长把大量空闲时间包进来,DB Time / Elapsed 的比值会被严重拉低。

解决:先和业务确认性能问题发生的具体时间段,然后用DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT手动创建快照,或者调整快照间隔(默认 60 分钟)到更细的粒度。分析时只选覆盖问题时段的那对快照。

4.2 把 DB Time 当成响应时间

现象:看到 DB Time 很大就认为系统慢,看到 DB Time 小就认为没问题。

原因:DB Time 是累计时间,不是单次请求的响应时间。它统计的是所有非后台进程在数据库上花的总时间,和并发数、请求量都有关系。

解决:DB Time 要和 Elapsed、CPU 核数一起看,算比值判断整体压力。单次请求的响应时间要看 Average Active Sessions(AAS)或者具体 SQL 的 Elapsed Time per Exec。

4.3 硬解析阈值生搬硬套

现象:Hard Parses 每秒超过 100 就急着改cursor_sharing。

原因:文档明确说cursor_sharing=similar存在 bug,可能导致执行计划不优。而且硬解析阈值和系统类型有关,DSS 系统和 OLTP 系统的标准完全不同。

解决:先确认 SQL 是否真的没有复用——看SQL with executions>1的比例,如果低于 80% 才考虑绑定变量。改cursor_sharing之前先在测试环境验证执行计划,优先从应用层改 SQL 写法。

4.4 忽略 RAC 相关的全局等待

现象:单实例分析没问题,RAC 环境下性能就是上不去。

原因:RAC 报告里有 Global Cache Load Profile 和 Global Cache Efficiency Percentages,如果Buffer access - remote cache %偏高,说明实例间数据传递频繁,互联网络可能成为瓶颈。

解决:关注Avg global cache cr block receive time和Avg global cache current block receive time,如果超过 1ms 就要检查互联网络。同时看Estd Interconnect traffic,评估网络带宽是否足够。

4.5 用命中率高低直接判断性能好坏

现象:Buffer Hit 98% 就认为没问题,或者低于 90% 就急着加内存。

原因:文档明确指出高命中率可能是假象——大量非选择性索引被频繁访问会造成命中率很高,但伴随大量db file sequential read。命中率的突变比绝对值更值得关注。

解决:命中率要和 Top 5 Timed Events、Top SQL 一起看。如果命中率高但 I/O 等待也高,说明问题不在缓存大小,而在 SQL 访问路径。如果命中率突然下降,查 top physical reads SQL,看是否有索引被删除或执行计划突变。

5. 从报告到行动:把 AWR 指标转成可执行的调优清单

5.1 建立基线比单次分析更重要

文档反复强调一个观点:单个报告的数据只说明应用的负载情况,绝大多数指标没有「正确」值,必须和基线对比。我一般会在系统稳定运行期采集 3~5 份 AWR 报告作为基线,记录 Load Profile 和 Instance Efficiency 的关键值。之后每次出现性能问题,先和基线对比,看哪些指标发生了突变。突变点往往就是问题源头。

比如Execute to Parse这个指标,计算公式是100 * (1 - Parses/Executions)。文档例子里差不多每 5 次执行需要 1 次解析,所以这个值在 80% 左右。如果基线是 90%,突然掉到 50%,说明解析次数暴增,要么是 SQL 没复用,要么是 shared pool 出了问题。如果这个值小于 0,说明 Parses 大于 Executions,通常意味着 shared pool 设置有问题或者语句效率极差,reparse 严重。

5.2 用 SQL 定位具体问题语句

AWR 报告里的 Top SQL 区域按不同维度排序,常用的有 Elapsed Time、CPU Time、Buffer Gets、Physical Reads。我一般按这个顺序查:

-- 查当前等待事件对应的 SQL(实时排查用) select s.sid, s.serial#, s.username, s.sql_id, s.event, s.wait_class, s.seconds_in_wait, q.sql_text from v$session s join v$sql q on s.sql_id = q.sql_id where s.status = 'ACTIVE' and s.wait_class <> 'Idle' order by s.seconds_in_wait desc; -- 查历史 SQL 统计(AWR 快照范围内) select sql_id, executions, elapsed_time/1000000 as elapsed_sec, cpu_time/1000000 as cpu_sec, buffer_gets, disk_reads, rows_processed, sql_text from dba_hist_sqlstat h join dba_hist_sqltext t on h.sql_id = t.sql_id where h.snap_id between &begin_snap and &end_snap order by h.elapsed_time_delta desc fetch first 20 rows only;

第一段查当前活跃会话的非空闲等待,直接定位到正在拖慢系统的语句。第二段查历史快照范围内的 SQL 统计,elapsed_time_delta是两次快照之间的增量,比绝对值更有参考意义。buffer_gets高说明逻辑读多,disk_reads高说明物理读多,rows_processed和executions的比值可以看出单次执行返回多少行。

5.3 共享池与解析问题的处理技巧

Shared Pool Statistics 里有两个指标很关键:Memory Usage %应该稳定在 75%~90%,太低说明 Shared Pool 设置过大带来管理负担,太高说明有争用。SQL with executions>1的比例如果太小,说明需要在应用中更多使用绑定变量。

我处理解析问题的顺序是:先看Soft Parse %,低于 95% 就查SQL with executions>1的比例;如果这个比例也低,说明 SQL 确实没复用,优先从应用层改绑定变量;如果应用层短期改不了,再考虑session_cached_cursors参数,让 fast parse 在 PGA 中命中。文档里提到 fast parse 是直接在 PGA 中命中的情况,设置session_cached_cursors=n后生效。这个参数对 OLTP 系统效果明显,但要注意每个 session 会占用额外 PGA 内存。

5.4 一个我踩过的坑

早些年我拿到一份 AWR 报告,看到log file parallel write排在 Top 5 第二位,占了 7% 的等待时间,第一反应是把 redo log 文件挪到更快的盘上。结果折腾了半天,发现真正的问题是应用端批量提交太频繁,导致 LGWR 写入压力大。后来我养成一个习惯:看到任何 I/O 相关等待,先查Physical Writes和Redo size的 Per Second 值,确认是数据库配置问题还是应用写入模式问题。如果是应用写入模式问题,换再快的盘也是治标不治本。

从那以后我每次分析 AWR 报告,都强制走一遍「DB Time / Elapsed → Top 5 Timed Events → 对应区域的详细指标 → Top SQL」这条链路,不跳步。这份《OracleAWR报告详细分析.pdf》把这条链路上的每个节点都讲到了,包括 RAC 环境下的全局缓存指标和常见等待事件的参数含义,适合放在手边当速查手册用。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询