Oracle AWR报告分析:从DB Time到等待事件,六步定位数据库性能瓶颈
2026/9/19 8:41:07 网站建设 项目流程

简介:面向Oracle数据库运维与调优场景,这份PDF文档围绕AWR(自动负载信息库)报告展开,从10g引入的快照对比机制讲起,说明如何通过Begin/End Snap、Elapsed与DB Time判断数据库繁忙程度,并结合实际案例演示CPU利用率计算,帮助DBA快速识别系统压力。文档特别强调批量系统中负载集中、快照区间选取不当会导致分析失真,并覆盖Buffer Cache、Shared Pool Size、Log Buffer等SGA区域查看,以及Load Profile关键指标解读。单个PDF文件共1.18MB,内容精炼,便于随时查阅。目前已有580人学习,适合具备一定SQL基础、希望系统掌握AWR报告解读方法并提升数据库性能优化能力的读者。

1. 从 DB Time 与 Elapsed 的比值判断数据库真实负载

拿到一份 AWR 报告,我第一步不是翻 Top 5 Timed Events,而是先看报告头部 Begin Snap 和 End Snap 之间的 Elapsed 与 DB Time。这两个数字的比值决定了后面所有分析是否值得继续。DB Time 不包含 Oracle 后台进程消耗的时间,本质上是服务器花在数据库运算(非后台进程)和等待(非空闲等待)上的总时间,即 DB Time = cpu time + all of nonidle wait event time。

举个例子,一份报告中 Elapsed 为 78.79 分钟,DB Time 只有 11.05 分钟,系统有 8 个逻辑 CPU(4 个物理 CPU),平均每个 CPU 耗时 1.4 分钟,CPU 利用率大约 2%(1.4/79)。这种系统压力非常小,可以直接判断数据库处于空闲状态。但另一种情况,Elapsed 为 59.51 分钟,DB Time 高达 466.37 分钟,8 个 CPU 总共可提供约 480 分钟的 CPU 时间,意味着 CPU 有 97% 的时间在处理 Oracle 的工作,这种数据库已经濒临饱和。所以第一步永远是算这个比值,它决定了你要不要继续往下读。

对于 5 年以上经验的 DBA,这里还要警惕一个隐蔽问题:批量系统的负载往往集中在某个时间窗口内,如果快照周期没有覆盖实际业务高峰,或者跨度太长把大量空闲时间也算进去,DB Time 会被严重平均化,导致误判。选快照区间本身就是一门手艺。

2. Load Profile 逐项拆解:Transaction、Parse 与 Redo 的关键阈值

Load Profile 是 AWR 报告的第二节,以 Per Second 和 Per Transaction 两个维度展示数据库负载概况。这一节没有绝对的“正确值”,但有几个公认的经验阈值值得记在脑子里。

2.1 Parses 与 Hard Parses:SQL 重用的两个关键信号

Parses 是 SQL 解析次数,包括 fast parse、soft parse 和 hard parse 三种。fast parse 指在 PGA 中直接命中(设置了 session_cached_cursors);soft parse 指在 shared pool 中命中;hard parse 则是完全重新解析。硬解析需要创建解析树和生成执行计划,开销昂贵。

经验阈值:每秒硬解析超过 100 次,说明绑定变量使用不好或共享池设置不合理;全部 Parses 超过每秒 300 次,意味着应用程序解析效率低下。一个典型报告片段:

Parses: 38.66 Hard parses: 0.03

这个硬解析比例非常健康,几乎是全部软解析。如果看到 Hard parses 每秒上百,第一反应不是调 cursor_sharing,而是去查应用代码里到底哪些 SQL 没有被绑定变量化。cursor_sharing=similar 这个参数存在 bug,可能导致执行计划不优,设置前要慎重。

2.2 逻辑读、物理读与 Redo 的关系

Logical reads 等于 Consistent Gets 加 DB Block Gets,反映的是数据库内存访问频率。Physical reads 是磁盘读,Physical writes 是磁盘写。这几个指标需要结合 Buffer Hit 一起看:

指标含义重点关注
Redo size每秒产生的日志大小(字节)数据变更频率,任务繁重程度
Logical reads每秒逻辑读的块数内存访问压力
Physical reads每秒物理读的块数磁盘 I/O 压力
Block changes每秒修改的块数DML 操作密度
User calls每秒用户 call 次数应用交互频率

注意一个容易被忽略的指标:Rollback per transaction,计算公式是Round(User rollbacks / (user commits + user rollbacks), 4) * 100%。如果每事务回滚率过高,说明数据库经历了太多无效操作,可能带来 Undo Block 竞争。一个报告里如果这个值超过 20%,我会先去查应用层是否频繁发生异常回滚,而不是急着调 undo 表空间大小。回滚本身就是一种资源消耗,治本要改应用行为。

2.3 Transactions 与 Executes 的组合判断

Transactions 反映事务吞吐量,Executes 反映 SQL 执行次数。如果 Executes 远大于 Transactions,说明每个事务内部执行了多条 SQL,这是正常现象。但如果看Execute to Parse %只有 89%,意味着每执行约 5 次就要解析 1 次,SQL 重用率还有提升空间。该指标计算公式为100 * (1 - Parses/Executions),如果出现负数,说明解析次数大于执行次数,通常意味着 shared pool 设置有问题或语句存在反复解析。

提示:单个报告的数据只说明应用负载情况,没有绝对的正确值。Load Profile 最大的价值在于与历史基线对比,如果每秒或每事务的负载变化不大,说明应用运行稳定。

3. Instance Efficiency 命中率:Buffer Hit 与 Library Hit 的边界条件

AWR 报告的 Instance Efficiency Percentages 一节集中展示了内存命中率。很多初学者只看 Buffer Hit,但实际调优时更要注意 Library Hit 和 Latch Hit 的组合,因为它们分别指向 SGA 中两个不同的资源池。

3.1 Buffer Hit Ratio 的适用场景与被误用的高命中率

Buffer Hit 表示进程从内存中找到数据块的比率,OLTP 系统通常要求 95% 以上。但一个高命中率不一定代表系统性能最优——大量非选择性索引被频繁访问时,会产生大量 db file sequential read,同时拉高命中率,这是一种假象。反过来,如果命中率突然增大,要检查 Top Buffer Get SQL 中是否存在大量逻辑读的语句;如果突然减小,要去查是否索引被删除或没有使用索引。

关于命中率的行业讨论经常被简化,实际上不同业务场景的合理区间差异很大:

  • OLTP 系统:Buffer Hit 低于 90% 应优先考虑增加 db_cache_size
  • DSS/数据仓库系统:直接读执行大型并行查询时,20% 也可以接受,此时关注 Physical reads 更实际
  • 批处理场景:关注命中率的同时更要关注Buffer Nowait %

Buffer Nowait 表示在缓冲区获得数据的未等待比例,一般需要大于 99%,否则可能已出现 buffer busy waits 争用。

3.2 Soft Parse、Library Hit 与 Shared Pool 的关系

Library Hit 表示从 Library Cache 检索到解析过的 SQL 或 PL/SQL 语句的比率,通常应保持在 95% 以上。低于 90% 时,加 shared_pool_size 只能治标,真正的问题往往在于 SQL 没有使用绑定变量。我先看 Shared Pool Statistics 里的两个值:

Memory Usage %: 47.19 -> 47.50 % SQL with executions>1: 88.48 -> 79.81

Memory Usage 长期稳定在 75% 到 90% 之间是合理的。如果太低,说明 shared pool 设置过大,带来额外管理负担;如果超过 90%,则会引起 SQL 老化,导致再次硬解析。% SQL with executions>1这个值如果太小,说明应用中大量 SQL 只执行了一次,基本没有被重用。这里有一个常见误用:把Oracle 11g 下载资源Oracle 安装教程 11g这类环境搭建问题与 shared pool 参数混为一谈。框架搭得再标准,SQL 写不好,命中率照样上不去。

3.3 Parse CPU to Parse Elapsd 与 Non-Parse CPU 的解读

Parse CPU to Parse Elapsd 的计算公式为100 * (parse time cpu / parse time elapsed),即解析实际运行时间占解析总时间(含等待)的比例,理论上越高越好。本例中只有 7.99%,意味着解析过程中有大量时间在等待资源,结合后面的 Latch 争用分析,能定位到是 library cache latch 还是 shared pool latch。

Non-Parse CPU 计算公式为round(100 * (1 - PARSE_CPU/TOT_CPU), 2),表示 SQL 实际执行时间占数据库总 CPU 时间的比例。如果这个值偏小,说明 CPU 时间被解析消耗掉了,而不是在执行查询。它会与 Execute to Parse 指标联动:二者都低,说明系统处于“频繁解析、少量执行”的亚健康状态。

提示:命中率统计帮助发现和预测系统将要产生的性能问题,属于未雨绸缪;而等待事件表明当前数据库已经出现性能问题需要解决,属于亡羊补牢。两部分的定位不同,不要混用。

4. Top 5 Timed Events 与等待事件:用 v$session 定位争用源头

Instance Efficiency 给出的是整体印象,真正确定性能问题要靠等待事件。Top 5 Timed Events 是报告概要的最后一节,按等待时间倒序列出最严重的 5 个等待,这是决定下一步调优方向的起点。

4.1 从 Top 5 判断系统当前状态

一个好的信号是 CPU time 排在第一位。当一个系统的 CPU time 不是第一,说明大部分时间没有在计算,而是在等某个资源。一段真实报告中的 Top 5 可能是这样:

Event Waits Time(s) Avg Wait(ms) % Total Call Time Wait Class CPU time 515 77.6 SQL*Net more data from client 27319 642 29.7 Network log file parallel write 5497 479 7.1 System I/O db file sequential read 7900 354 5.3 User I/O db file parallel write 4806 347 5.1 System I/O

这里 CPU time 排第一,说明系统整体健康。但如果看到log file parallel write占比较高,要确认日志文件是否放在慢速存储上,以及是否频繁触发 log 切换。如果看到buffer busy wait进入 Top 5,就需要查看 Buffer Wait 和 File/Tablespace IO 部分,识别哪些文件导致问题。

4.2 db file sequential read 与 db file scattered read 的先后判断

db file sequential read 说明在单个数据块上大量等待,通常由表连接顺序糟糕或使用非选择性索引引起。db file scattered read 则与全表扫描或 fast full index scan 有关。这两者的处理优先级有区别:

等待事件常见原因优先动作
db file sequential read索引扫描、表连接顺序问题检查连接顺序、索引选择性
db file scattered read全表扫描确认扫描是否必要,必要时添加索引
buffer busy wait热块、freelist 竞争定位 block 类型,调整存储参数

对于 db file scattered read,可以通过参数optimizer_index_cost_adj微调优化器行为。该参数是一个百分比,默认值 100,含义是FULL SCAN COST / INDEX SCAN COST。当n% * INDEX SCAN COST < FULL SCAN COST时,Oracle 会选择使用索引。通常把它调到 30 到 50 之间,可以让优化器更倾向于索引扫描。但调整前要对具体 SQL 对比全表扫描和索引扫描两种执行计划的 cost,不要盲目设置。

4.3 buffer busy waits 的分层定位 SQL

定位 buffer busy waits 时可以借助相关的动态性能视图,获取该事件的具体等待位置。常见做法是查询v$session_wait关联dba_segmentsv$sql。例如获取产生事件的 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';

这段 SQL 的核心逻辑是通过 v$session 建立 v$sql 与 v$session_wait 之间的关联,三个视图的连接键分别是 sql_address 和 sql_hash_value。如果查询结果为空,说明 SQL 已经从 shared pool 中被淘汰,需要根据 file# 和 block# 反查对象。

获取等待的块类型及所在 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';

注意这里 p1 代表 file#,p2 代表 block#。在 Oracle 9i 中 p3 是等待原因编号 id,而在 10g 中 p3 变成了 class#,即块类型编号。判断结果时,如果等待位于 Segment Header,要考虑增加 freelists 或 freelist groups;如果在 undo header,需要增加回滚段;如果在 data block,常见的处理手段是增大 pctfree 扩大数据分布,或者减小块大小降低单个块中的行数,也可以增加 initrans 减少 ITL 竞争。

提示:Oracle 9i 中对 buffer busy waits 事件的参数是 file#、block#、id;10g 及以后,p3 参数从 id 变成了 class#,诊断脚本要按版本区分。

5. Shared Pool 的 SQL 老化机制与内存使用率验证

AWR 报告的末尾有一个经常被忽略的部分——Shared Pool Statistics 揭示的是 SQL 在共享池中的生命周期。它不像等待事件那样直接给出问题,但为前面所有命中率指标提供了一个解释框架。

5.1 Memory Usage 稳定区间背后的老化逻辑

Shared Pool 的 Memory Usage % 反映共享池内存使用率。理想情况下应稳定在 75% 到 90% 之间。低于 75% 说明 shared pool 设置过大,多余的内存不仅浪费,还会增加管理负担,极端情况下可能导致性能下降;高于 90% 则意味着共享池空间紧张,SQL 老化速度加快,出现频繁的硬解析。

老化机制是理解这一节的关键:当新的 SQL 需要解析且共享池没有空闲空间时,Oracle 通过 LRU 算法将最久未使用的 SQL 淘汰出库。如果 Memory Usage 长期超过 90%,会导致刚被解析的 SQL 很快被挤出,形成“解析-淘汰-再解析”的恶性循环。这种情况在DBeaver Oracle 数据库连接或Navicat 连接 Oracle这类工具频繁提交非绑定变量 SQL 时尤其常见——工具的 SQL 生成方式本身就是问题的一部分。

5.2 SQL with executions>1 与 Memory for SQL w/exec>1 的组合分析

% SQL with executions>1表示执行次数大于 1 的 SQL 数量占比,Memory for SQL w/exec>1表示这些 SQL 消耗共享池内存的占比。二者通常非常接近,但有一种例外:某些查询任务消耗的内存份额与其执行频率不成比例,这种 SQL 往往占据大量 shared pool 却不常执行,反而推高内存使用率。

排查这类 SQL 时可以通过数据字典视图定位最占共享池空间的游标:

select sql_id, executions, sharable_mem, sql_text from v$sql where sharable_mem > 1000000 order by sharable_mem desc fetch first 20 rows only;

fetch first 20 rows only是 12c 及以上版本的语法,11g 及以下需要替换为where rownum <= 20。sharable_mem 单位是字节,筛选大于 1MB 的游标通常能抓住大头。executions 很低的游标却占据了大量共享内存,说明这些 SQL 是一次性业务逻辑,需要从应用层面优化。

5.3 结合 AWR 报告验证调整效果的收尾方法

通过 AWR 报告的六个核心部分,可以拼出数据库健康的完整画像。每部分对应的性能问题如下所示:

报告章节核心关注点常见调整手段
DB Time vs Elapsed系统整体负载时间窗口选择
Load Profile解析、事务、逻辑读绑定变量、应用层优化
Instance Efficiency命中率、LatchSGA 参数调整
Top 5 Timed Events等待事件存储、SQL、并发策略
Shared Pool StatisticsSQL 老化、内存使用shared_pool_size、cursor_sharing
RAC Statistics节点间通信Interconnect 带宽、消息队列

按这个顺序读报告,从头部负载判断到尾部 SQL 生命周期,每一层都在为下一层的分析提供上下文。先把时间窗口选对,再逐项核对指标,最后落到等待事件和 SQL 层,整个分析链条才算完整。最后可以用一条 SQL 快速收集当前数据库的等待情况,与 AWR 报告形成交叉验证:

select event, total_waits, time_waited_micro / 1000000 as time_sec from v$system_event where wait_class <> 'Idle' order by time_waited_micro desc fetch first 10 rows only;

这个查询过滤掉 Idle 类等待,直接看非空闲等待的累计时间。如果当前等待分布与 AWR Top 5 明显不同,说明负载已经发生了变化,AWR 报告的结论需要重新评估。把这份 PDF 里的方法论消化完,你面对任何一份 AWR 时都不会再被那一大串百分比淹没——拿着这六个维度逐层拆解,每个数字都能讲出它背后的业务含义。

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

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

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

立即咨询