☰
Oracle AWR报告分析实战:从快照生成到CPU瓶颈定位的DBA指南
2026/10/12 7:22:22 网站建设 项目流程

简介:Oracle数据库AWR报告分析(作者黄伟波)是一份面向数据库管理员与性能优化人员的PDF学习资料,系统讲解了AWR(自动工作负载仓库)报告从导出到分析的全流程。资源包共1个PDF文件,大小约7.13MB,内容涵盖AWR概述、统计信息分类、STATISTICS_LEVEL参数作用,以及负载概况、SQL语句报告、等待事件、活动会话历史等核心模块。目前已有226人学习。文档不仅介绍了通过企业管理器或命令行生成标准报告、基线对比报告和时段对比报告的方法,还说明了收集间隔、保留期限及快照管理等维护操作;在分析层面,重点剖析了缓冲区缓存命中率、硬解析次数、逻辑读取次数等关键指标,帮助读者快速定位性能瓶颈并优化数据库配置。整份资料结构清晰,从导出流程到分析实践均有涉及,适合希望系统掌握AWR报告分析方法的DBA参考使用。

1. 为什么Oracle数据库AWR报告分析是DBA的体检报告

接手一套Oracle数据库,我做的第一件事不是翻告警,而是先拉一份AWR报告。Oracle数据库AWR报告分析这个习惯,让我在几次“数据库突然变慢”的故障里都在一小时内找到了方向。AWR(Automatic Workload Repository)会自动每隔一段时间给数据库拍一张状态快照,报告就是两张快照之间的差值,把等待事件、SQL执行、IO流量这些体检数据一次性摊开给你看。

可惜不少人和最初的我一样,打开报告只看一眼Top 5 Timed Events就关掉,觉得后面的数字密密麻麻。这种用法等于只测了体温,没看胸片。这篇笔记写给刚接触Oracle的运维同学,也写给要临时救火的开发。我会从怎么生成报告讲起,再到关键段落怎么读、哪些地方最容易踩坑,最后给出一套能直接复制的CPU瓶颈定位套路。读完你至少能独立完成一次AWR报告分析,并知道改完以后用什么来验证自己没瞎折腾。

2. 从快照到报告:生成AWR报告的最小命令与参数

不管分析能力多强,拿不到一份高质量报告都是白搭。AWR报告的数据来源是快照,所以先搞清楚快照怎么产生、怎么保留,再看生成命令。

2.1 快照机制:AWR报告的数据来源与保留策略

AWR从Oracle 10g开始成为默认性能仓库,后台MMON进程按固定间隔采集当前实例的运行状态,把v$sysstat、v$session_event、v$active_session_history等视图汇总后的统计数据写入SYSAUX表空间对应的dba_hist_*系列表。每次采集的结果就是一个快照。AWR报告不是实时数据,而是两个快照之间的差值,所以搞清楚快照间隔和保留策略,比背报告内容更重要。

默认情况下快照间隔是60分钟,保留8天。不过在真实场景里,我建议针对大促或大变更手动加快照。修改这两个参数用dbms_workload_repository包:

BEGIN DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS( retention => 43200, -- 单位分钟,30天 interval => 30 -- 单位分钟,每30分钟采样一次 ); END; /

interval是最小间隔,不能小于10分钟,否则MMON采集开销会明显变大。retention设太大会撑大SYSAUX,太小会导致历史数据不够用。我一般生产环境保留14天,再配合基线把重要时段钉住。

如果希望某些重要时段的快照不被自动清理,可以用CREATE_BASELINE钉住一段快照范围。例如每年大促前,我先为高峰时段创建基线:

EXEC DBMS_WORKLOAD_REPOSITORY.CREATE_BASELINE( start_snap_id => 800, end_snap_id => 805, baseline_name => 'MONTHLY_PEAK_202504');

基线相当于给快照上了保险,自动清理任务会跳过被标记为基线的快照。这个习惯能救急救命,后面第4章还会提到。

2.2 用awrrpt.sql生成报告:命令与参数说明

生成报告最常用的方式是调用Oracle自带脚本,在sqlplus里执行:

sqlplus / as sysdba SQL> @?/rdbms/admin/awrrpt.sql

首先会问报告格式,输入html或text。我一般选html,浏览器打开方便;但如果是丢给脚本做自动化归档,选text更好解析。接着问“Number of days”,输入1表示列出最近1天的快照;然后要求输入起始和结束快照ID。

生成之前先查快照更稳妥,避免凭记忆输错编号:

SQL> select snap_id, begin_interval_time, end_interval_time from dba_hist_snapshot where begin_interval_time > sysdate - 1 order by snap_id;

snap_id决定报告窗口。选快照时尽量选完整的业务周期,比如上午10:00到11:00,而不要选10:15到10:30这种半截窗口。AWR报告会输出到当前目录,文件名叫类似awrrpt_1_800_805.html的东西;如果找不到文件,检查sqlplus当前目录,或者先用spool指定输出路径再执行脚本。

实际工作中,很多人会遇到目录权限问题。如果服务器上你自己不是目录所有者,建议先cd /tmp,再进sqlplus,这样报告生成在/tmp下,避免“文件明明生成了但没权限看”的尴尬。

2.3 手工快照与实例级报告:awrrpti.sql为什么经常用

需要对比特定时间点时,可以先创建快照再做操作,操作后再补一张快照:

SQL> exec dbms_workload_repository.create_snapshot();

这个命令会立即触发一次采集,通常十几秒到几十秒完成。比如发布存储过程时,发布前后各打一张快照,报告就能准确反映新存储过程对系统的冲击。

如果数据库是多实例环境,awrrpt.sql默认生成当前连接实例的报告,想指定实例需要用awrrpti.sql:

SQL> @?/rdbms/admin/awrrpti.sql

它会多问一个instance number。实例号可以先查:

SQL> select instance_number, instance_name, startup_time from dba_hist_database_instance;

在RAC环境下,这一步最容易漏。我见过有人分析了一个节点就下了全库结论,结果问题其实出在另一个节点的全局缓存等待上。第4章会再展开说这个坑。

3. 报告里面看什么:Top Events、SQL统计与IO联动的读法

拿到报告后,不要从头到尾背数据,按“事件→SQL→IO”的顺序读下去,思路会清晰很多。

3.1 Top 5 Timed Events是起点,但不是终点

报告靠前位置有一块Top 5 Timed Events,它告诉你周期内数据库把时间花在了哪里。常见事件的含义先列出来:

等待事件归类常见含义
CPU time非等待会话正在CPU上运行,通常排第一
db file sequential readUser I/O单块随机读,常见于索引回表
db file scattered readUser I/O多块读,常见于全表扫描
log file syncCommit提交等待redo落盘,常见于高频提交
enq: TX - row lock contentionApplication行锁或事务锁等待

注意一个容易翻车的判断:CPU time排第一,不一定就是服务器CPU不够。也许是SQL写得差,大量逻辑读把CPU耗尽了。如果只看事件排行就加CPU核数,下次报告大概率还是原样。要结合第二个指标“Wait Class”:User I/O高,优先看SQL扫描和物理读;Concurrency高,优先看热块和锁;Application高,优先看应用层锁等待。

3.2 SQL by Elapsed Time:定位大头SQL的五个字段

报告里“SQL ordered by Elapsed Time”按SQL总耗时倒序排列。查看时要同时关注五个字段:

  • SQL ID,用于绑定游标查询
  • Elapsed Time,本周期内SQL消耗的总时间
  • Executions,执行次数
  • Elapsed Time per Exec,平均每次执行耗时
  • %Total DB Time,占总DB Time的百分比

如果一条SQL占总DB Time的30%以上,基本可以锁定了。先取SQL文本:

SQL> select sql_text, sql_id from dba_hist_sqltext where sql_id='abcdefgh12345';

再看执行计划:

SQL> select * from table(dbms_xplan.display_cursor('abcdefgh12345',0));

第二个参数是child number,写0代表默认子游标。如果SQL执行计划因绑定变量而分裂成多个子游标,先查v$sql确认child_number再取计划。注意,只看总Elapsed Time还不够,要同时看Executions。如果一条SQL执行了100万次,单次0.1秒,总耗时也很大;这时候优先考虑减少调用次数而非重写SQL。如果单次执行几十秒、执行次数很少,那就是典型的大事务/大查询,优化执行计划更关键。

3.3 IO Profile和Instance Activity:把单点事件连成资源画面

IO Profile在报告后半段,给出每秒和每事务的IO数据。重点看:

  • Redo size,反映事务密集程度
  • Logical reads,buffer cache中的逻辑读
  • Physical reads,从磁盘读入buffer cache的量
  • Physical writes,写盘量

如果Physical reads与Logical reads的比值高于10%,说明大量数据没进buffer cache,SQL每次都要从磁盘捞,可能存在SGA不足或扫描型SQL。如果比值低,但Top Events显示User I/O高,那可能不是数据文件读慢,而是同步写或日志写慢。

Instance Activity里有几个计数器值得扫一眼。parse count (total)和parse count (hard)之差很大,说明硬解析比例高,shared pool压力大;table scans (long)次数高,说明存在低效全表扫描;session logical reads高,说明逻辑读压力大。

把三块串起来才是AWR分析的真正打开方式。举例:Top Events显示CPU time占70%,SQL by Elapsed Time里某条SQL占40%,IO Profile物理读不高,那大概率不是I/O问题,而是SQL在CPU上做了大量运算,比如笛卡尔积、类型转换导致索引失效、或者函数包级变量刷新频繁。接下来去看执行计划,而不是去调存储。

4. AWR报告分析最常见的5个坑:现象、原因、对策

报告会生成只是第一步,读错报告才要命。下面这5个坑我基本都踩过,每条按现象、原因、解决展开。

4.1 快照间隔太短:看起来数字齐全,其实没有代表性

现象:业务午高峰是10:00到12:00,为了抓问题在10:05和10:25各打一个快照,生成报告后所有数值都偏低,Top Events分布也奇怪,甚至和业务感知对不上。

原因:AWR内部采样频率不是秒级的,平均约15分钟一次。间隔过短时,很多统计是通过少量样本插值出来的,会漏掉峰值;而且10:05到10:25可能还没包含真正的高峰动作,报告自然没有代表性。

解决:快照间隔至少要覆盖一个完整业务单元。日常用默认60分钟就够了;手工快照也尽量隔20到30分钟以上。如果问题只持续几分钟,那就不要强行用AWR,直接查ASH(dba_hist_active_sess_history),用秒级采样补足。

4.2 只读Top Events,忽略DB Time和等待事件分类

现象:报告里db file sequential read排第一,立刻判断I/O瓶颈,加索引、扩缓存,一周后报告还是老样子。

原因:db file sequential read是单块读,单次等待时间短但次数多。真正要看的不是它排第几,而是它消耗的DB Time占比多少。如果数据库总DB Time本来就小,这个事件排第一也没有调优价值。另一个点是没有看Wait Class,把User I/O和System I/O混为一谈。

解决:先看报告顶部的DB Time。DB Time很小,后续所有百分比都要降权。再看Wait Class,如果User I/O类事件占比不高,先不要动存储或SQL。正确顺序是:DB Time → Top Events → SQL Statistics → IO Profile。每一步都以前一步的数据做筛选条件,才不会跑偏。

4.3 基线选错:拿业务低峰对比业务高峰

现象:拿晚上23点空闲快照和白天10点忙时快照对比,得出“数据库使用量暴增”的结论,吓出一身冷汗。

原因:AWR对比报告只负责算差值,不负责判断两个时间段业务量是否可比。晚间低峰Executions可能只有白天的十分之一,任何等待事件自然也会大幅下降,对比得出的“下降/上升”没有意义。

解决:对比前先看Load Profile里的Executions、User calls、Redo size。如果量级差出一倍以上,先校准业务量再说。更好的做法是用awrddrpt.sql做期间对比,选择同星期几、同时间段。比如上周二10:00-11:00对比这周二10:00-11:00,而不是拿周一和周日硬比。我要求团队每周存一份业务高峰基线报告,就是为了让对比时有据可依。

4.4 RAC下只出单实例报告,漏掉节点间等待

现象:4节点RAC,每个节点单独拉AWR报告都正常,但应用整体延迟高,最后发现是gc cr block busy事件在作怪。

原因:awrrpt.sql默认只取当前连接实例的快照。单节点报告看不到全局缓存融合(Cache Fusion)带来的跨节点流量和块竞争,尤其当多节点频繁读写同一数据块时,每个节点看自己都“正常”,合在一起就是慢。

解决:RAC环境生成全局报告用awrgrpt.sql,它启动时会询问实例范围,可选所有实例,输出一份聚合报告。重点关注Global Cache Statistics和gc类等待事件。如果发现gc cr block busy占比高,问题通常出在应用频繁跨节点访问热数据,要先从应用分区/实例亲和入手,而不是加带宽。

4.5 快照有缺口:报告生成失败或出现N/A

现象:生成报告时报错“snap_id xxx doesn't exist in this instance”,或者报告某些段落显示N/A。

原因:最常见是SYSAUX表空间满,AWR自动清理了一部分历史快照,导致起止快照之间缺了中间点;另一个原因是实例在快照期间重启过,前后两段数据来自不同生命周期,统计数据对不上。

解决:先查dba_hist_snapshot确认快照连续性。如果只是某个实例缺快照,用awrrpti.sql限定存在的实例号。想避免快照过期,把retention调大,或为关键窗口用CREATE_BASELINE钉住数据。至于N/A,有些统计项本来就不是所有环境都采集,比如Exadata上的IO统计,在普通单实例就没有,这种可以忽略。

5. 实战套路:用AWR报告定位一次CPU过高引发的慢查询

第4章的坑都规避之后,下面用一套可复制的流程,走一遍“CPU高”的排查。这个方法在Oracle EBS、制造业非标工单等业务系统上都适用。

5.1 先看三样东西:时间段、实例、变更记录

拿到报告,不要直接跳进Top Events。先读报告头部:数据库名、实例名、主机、报告时段。确认这个时段是不是业务峰值,快照覆盖了多久。再看最近有没有变更:应用是否发布新版本、Oracle存储过程有没有被改动、DBA有没有调过优化器参数。变更记录是分析执行计划变化的钥匙。

举个例子:

时间窗口:10:00-11:00,业务峰值,报告覆盖60分钟 变更记录:10:05上线新存储过程,更新了一批订单数据

看到这个信息,下面就可以把AWR报告锁定在10:05之后的快照区间,目标明确很多。

5.2 按Load Profile→Top Events→SQL排序逐段锁因

先看Load Profile里的DB Time(s)和Elapsed Time(s)。DB Time是实例内所有会话消耗的数据库时间,可以大于Elapsed Time,因为并行查询或大量并发会话会在同一秒内吃满多个CPU。如果DB Time远大于Elapsed Time,说明系统在这段时间严重排队。

假设这个案例里Top Events有70%是CPU time,20%是db file sequential read。SQL Statistics里第一条SQL占用DB Time的65%,执行次数只有2次,单次Elapsed Time接近5分钟。拿到SQL ID后,我习惯带统计信息查看执行计划:

SQL> select * from table(dbms_xplan.display_cursor('abcdefgh12345',0,'ALLSTATS LAST'));

第三个参数ALLSTATS LAST会显示上一轮执行的实际行数、内存使用和代价,比默认计划更接近事实。执行结果里很有可能出现类似TABLE ACCESS FULL的步骤,而代价基数很大。根据经验,这类问题多半是SQL里嵌了自定义函数,导致每一行都要调用函数计算,或发生了类型隐式转换,让索引失效。解决方向通常是重写SQL、加函数索引,或者把函数计算移到应用层。

5.3 调整后怎么验证:用同口径快照对比

不要只看应用说“变快了”。我改完SQL后会在同一时段(比如第二天10:00-11:00)生成新的AWR报告,对比下面几个指标:

指标调整前调整后
DB Time(s)420180
SQL Elapsed Time(s)30020
Physical Reads18M110K
Top Event排名CPU 70%CPU 30%

重点看SQL平均单次执行时间和Physical Reads是否大幅下降。如果DB Time降了但Top Events变了,说明瓶颈可能转移,比如原来卡在CPU,现在卡在log file sync,还要继续分析。业务量可比性在这个环节很重要,必须对比相同时间长度、相同业务类型。用AWR验证AWR,比抓一堆实时会话更客观,也更容易说服同事。

6. 把AWR报告分析变成长期可依赖的资产

到这里,生成、解读、避坑、实战都覆盖了。最后分享三个让我真正从“救火”变成“防火”的习惯。

6.1 用awrddrpt.sql做期间对比,提前发现劣化

不要等故障再拉报告。我每周一早上会跑一次awrddrpt.sql,对比上周日同一时段的两个时间段:

SQL> @?/rdbms/admin/awrddrpt.sql

它会要求选择两个时间段,各自输入起止快照,生成一份对比报告。报告会把Load Profile、Top Events、SQL统计并列出来,变化率用百分比标红。如果某条SQL的Elapsed Time连续两周上升,就该提前找开发评审,而不是等它变成故障。

6.2 用ASH补足AWR的秒级黑匣子

AWR粒度分钟级,如果问题只持续两三分钟,报告可能被平均值冲淡。这时我用ASH查秒级采样:

select session_state, wait_class, event, sql_id, count(*) from dba_hist_active_sess_history where sample_time between to_timestamp('2025-04-10 10:00:00','yyyy-mm-dd hh24:mi:ss') and to_timestamp('2025-04-10 10:05:00','yyyy-mm-dd hh24:mi:ss') group by session_state, wait_class, event, sql_id order by count(*) desc;

这段SQL能看到那一小段时间内活动会话都在等什么,弥补AWR在短时问题上的盲区。AWR负责看宏观,ASH负责看局部,两者配合才是完整的性能分析手法。

6.3 定期归档AWR报告,建立自己的性能基线库

我吃过不保留基线的亏,半夜被电话叫起来,领导问“为什么比上周慢”,手里却没有上周报告。从那以后,每周归档AWR成了固定动作。每次分析完报告,我会把html改名为实例名_起止时间.html放到归档目录,并记录当时业务变更。自动化可以用crontab调sqlplus执行awrrpt.sql,但要注意脚本对快照ID的判断,别把空的交互式输入留过夜。简单起见,先手动跑一个月,等流程稳定再写定时任务。

AWR报告分析并不需要多高深的理论,它更依赖连续的数据和细致的读法。先把快照管好,把Top事件、SQL统计、IO profile按顺序读完,大部分性能问题都会自己浮出来。希望帮到你。

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

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

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

立即咨询