如何通过Oracle AWR分析Undo表空间争用:优化回滚段分配与长事务 说起Undo表空间争用,很多DBA的第一反应是去AWR报告里找“Undo Waits”。但实际情况是,AWR报告本身并不会直接给你标出一个“争用”的结论。真正的诊断,需要你像侦探一样,串联起几个关键视图的数据,才能揪出问题的
说起Undo表空间争用,很多DBA的第一反应是去AWR报告里找“Undo Waits”。但实际情况是,AWR报告本身并不会直接给你标出一个“争用”的结论。真正的诊断,需要你像侦探一样,串联起几个关键视图的数据,才能揪出问题的元凶。
核心思路其实很清晰:先查V$UNDOSTAT看MAXCONCURRENCY是否持续≥20或频繁冲到50+,结合UNDOBLKS与TXNCOUNT的突刺来判断Undo压力;再用DBA_UNDO_EXTENTS检查EXPIRED区块占比是否低于20%;接着联合V$SESSION与V$TRANSACTION定位那些“占着茅坑不拉屎”的INACTIVE长事务;最后,确保undo_management=AUTO,合理设置undo_retention并排查底层存储异常。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
V$UNDOSTAT 看 UNDO 压力峰值是否持续超标AWR报告不直接说“undo争用”,但它的数据源头v$undostat视图却藏着所有秘密。这里的关键在于,不要只看平均值,必须盯住峰值。每10分钟一个的快照里,如果undoblks(使用的Undo块数)和txncount(事务总数)出现异常突刺,尤其是当maxconcurrency(最大并发事务数)长期在20以上,甚至频繁跳到50+,那基本可以断定,事务正在激烈地争夺回滚段头或区的分配锁。

具体怎么操作?给你几个实战建议:
SELECT BEGIN_TIME, END_TIME, UNDOBLKS, TXNCOUNT, MAXCONCURRENCY FROM V$UNDOSTAT ORDER BY BEGIN_TIME DESC FETCH FIRST 20 ROWS ONLY,重点关注最近20个快照。MAXCONCURRENCY持续高企,并且对应的UNDOBLKS增长速度远远超过TXNCOUNT(比如事务数只涨了2倍,Undo块却暴涨了5倍),那大概率是有长事务或者未提交的事务卡住了空间。UNDOBLKS的单位是数据库块(通常是8KB),不是字节,计算大小时可别搞错了。DBA_UNDO_EXTENTS 判断状态分布是否失衡Undo表空间爆满,很多时候问题不出在总量不够,而是内部状态“堵车”了——ACTIVE(活跃)和UNEXPIRED(未过期)的区块堆积如山,而EXPIRED(已过期)可回收的区块却少得可怜。这通常意味着undo_retention参数设得太长,或者空间回收机制被阻塞了。一个健康的状态是,STATUS = 'EXPIRED'的区块应该占到总量的30%到60%,如果低于20%,那就亮起红灯了。
实操时,可以这么干:
SELECT STATUS, SUM(BLOCKS) BLOCKS_CNT, TRUNC(SUM(BLOCKS)*8/1024) SIZE_MB FROM DBA_UNDO_EXTENTS WHERE TABLESPACE_NAME = 'UNDOTBS1' GROUP BY STATUS(记得把UNDOTBS1换成你实际的表空间名)。ACTIVE和UNEXPIRED加起来占比超过90%,而EXPIRED几乎为0,那么你的首要任务不是急着给表空间扩容,而是应该立刻去排查长事务(见下一节)。UNEXPIRED占比过高,也可能是因为undo_retention被设成了86400秒(24小时)但表空间又没有开启自动扩展,导致Oracle不敢回收空间。这种情况下,调低retention值往往比增加数据文件更治本。V$TRANSACTION 的 START_TIME这里有个常见的误区:以为查V$TRANSACTION.START_TIME就能找到所有长事务。其实不然。这个时间只记录了事务的开始时刻,但很多“长事务”其实是空闲连接挂着未提交(比如应用层连接池没有设置超时)。这类事务在V$TRANSACTION里能看到,但在V$SESSION视图里,其STATUS却是INACTIVE,SQL_ID也是空的。只盯着一个视图,会漏掉至少一半的问题。
正确的做法是联合查询:
SELECT s.sid, s.serial#, s.username, s.status, s.sql_id, t.start_time, t.used_ublk, t.used_urec FROM V$SESSION s JOIN V$TRANSACTION t ON s.saddr = t.ses_addr ORDER BY t.start_time。STATUS = 'INACTIVE'并且USED_UBLK > 10000的记录——这基本就是“占着大量Undo块却不干活”的典型。ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE来清理。动手之前,如果想了解一下它最初在做什么,可以先通过SELECT sql_text FROM V$SQL WHERE sql_id = 'xxx'查询一下(如果SQL还在共享池里的话)。rollback_segments 参数这里必须强调一个原则:在Oracle 9i之后默认启用的AUM(自动Undo管理)模式下,不要去动rollback_segments这个参数。它是手动管理模式的遗留产物,现在强行指定它,很可能导致实例启动失败,或者回滚段无法自动伸缩。这可不是优化,是技术倒退。
真正应该关注的调整点在这里:
undo_management是AUTO:执行SHOW PARAMETER undo_management。undo_retention参数,以及Undo表空间是否开启了AUTOEXTEND。undo_retention。undo_retention设置在900到3600秒(15分钟到1小时)之间。这个区间足以覆盖绝大多数事务,再设高收益极低,反而会拖慢空间回收速度。最后,分享一个最常被忽略的排查点:Undo表空间的底层存储状态。数据文件路径的权限、磁盘剩余空间、ASM磁盘组是否离线……这些底层异常通常不会直接反映在AWR报告或数据库错误日志里,但它们可能导致V$UNDOSTAT中的UNDOBLKS突然归零或增长停滞。所以,在深究数据库视图之前,不妨先看一眼操作系统的日志,有没有文件写入失败的记录。很多时候,问题就藏在这些基础环节里。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述