ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Oracle回滚段巡检:状态检查与异常处理实战

2026/9/7 18:49:34 拓冰建站 浏览量
Oracle回滚段巡检:状态检查与异常处理实战 数据库巡检做到第 17 个脚本终于轮到回滚段了。在 Oracle 的日常运维里回滚段Rollback Segment算得上最容易被忽略、但一出问题就让人头皮发麻的组件之一。事务回滚要靠它读一致性要靠它闪回查询也要靠它它一旦状态异常轻则 SQL 报错重则整个实例直接挂掉。今天这篇就把“检查所有回滚段的运行状态”这件事讲透为什么要巡、SQL 怎么写、结果怎么判、真出问题怎么处理。这套巡检脚本我一直在生产库上跑从 Oracle 9i 时代跑到现在的 19c手动回滚段和自动 Undo 管理模式都经历过。你只要把后面的 SQL 存成文件定期执行并保留输出就能对回滚段的健康状态做到心里有数。适合的读者包括负责 Oracle 日常巡检的 DBA、刚入门想搞懂 Undo 机制的运维同学以及被 ORA-01555 折磨过、想系统排查问题的人。1. 回滚段巡检到底在查什么1.1 回滚段在数据库里的“本职岗位”先花两分钟把回滚段的定位说清楚。Oracle 里的回滚段本质上是一块专门存放“数据修改前镜像”的存储区域。当一个事务执行 UPDATE、DELETE 或 INSERT 时Oracle 会先把修改前的数据写入回滚段然后再去改数据块。这样做有三个直接好处事务执行到一半想回滚可以拿回滚段里的旧数据恢复现场其他会话在事务未提交期间查询可以基于回滚段构造读一致性的快照不会看到“改了一半”的数据闪回查询、闪回版本查询这类功能同样依赖回滚段里保留的历史镜像。你可以把回滚段想象成记事本的“撤销栈”。我们写文档时按 CtrlZ 能一步步退回去靠的是编辑器记录的历史操作数据库里的回滚段就是这个历史操作记录区只不过它的容量有限、内容会循环复用而且一旦“历史记录”被覆盖旧的读操作就会报错。理解了这层机制你就会明白回滚段巡检不是例行公事而是直接关系到底层事务能不能正常提交、报表查询会不会报 ORA-01555、数据库会不会因为回滚段损坏而 crash。它属于那种“平时看不见、出事就是大事”的组件巡检的价值恰恰在于把隐患暴露在故障发生之前。1.2 状态检查为什么是巡检的第一优先级回滚段的运行状态是判断整个 Undo 子系统是否健康的“体温计”。如果回滚段的状态不是正常的 ONLINE或者回滚段的扩展行为异常、事务争用严重那么数据库的性能和稳定性都会受到直接影响。我在生产环境里见过几种典型的回滚段故障表现。比较常见的是回滚段状态变成 OFFLINE 或 PARTLY AVAILABLE这时候依赖该回滚段的事务可能直接报错另一种是回滚段不断扩展把 Undo 表空间撑满导致 DML 操作因为无法分配新的区而挂起还有一种是回滚段头部块出现损坏实例启动或事务提交时直接异常终止。这些问题有一个共同点早期几乎没有任何业务层面的报错只有通过定期巡检回滚段状态、空间使用和竞争情况才能提前发现趋势。这也是为什么脚本篇第 17 个就聚焦在这里——状态巡检是所有后续分析比如 ORA-01555 排查、Undo 空间规划的地基。1.3 自动 Undo 管理模式下还需要看回滚段吗这可能是不少人的疑惑现在数据库默认都是 UNDO_MANAGEMENTAUTO自动 Undo 管理模式回滚段都由 Oracle 自动管理了还有必要手工巡检吗答案是不仅有必要而且更重要。自动管理模式只是意味着回滚段的创建、删除、在线、离线由数据库自动完成但回滚段的运行状态、扩展趋势、事务竞争、空间使用率这些指标仍然需要通过数据字典视图来观测。Oracle 自动管理的是“操作”不是“健康监测”它不会主动告诉你 Undo 表空间快满了、也不会提醒你某个回滚段的热度异常偏高。另外如果你维护的是老系统仍然在使用手动回滚段管理模式UNDO_MANAGEMENTMANUAL配合 RBS 表空间那巡检脚本里的状态字段就显得更加关键了因为手动模式下回滚段的 ONLINE/OFFLINE 状态完全依赖 DBA 的判断出问题的概率也更高。所以下面的脚本我会同时兼容这两种模式视图和字段以 Oracle 官方数据字典为准。2. 用来检查回滚段运行状态的 SQL 脚本拆解2.1 基础状态巡检先看清每个回滚段当前怎么样我平时巡检时第一步永远是最朴素的状态查询查 DBA_ROLLBACK_SEGS 视图。这个视图记录了所有回滚段的元数据信息包含段名称、所在表空间、状态、实例编号等关键字段。脚本如下SELECT SEGMENT_NAME, TABLESPACE_NAME, STATUS, INSTANCE_NUM, DBA_ROLLBACK_SEGS.SEGMENT_ID, XACTS, EXTENTS, RSSIZE, WRITES, OPTSIZE, HWMSIZE, SHRINKS, AVESHRINK, AVEACTIVE FROM DBA_ROLLBACK_SEGS LEFT JOIN V$ROLLSTAT USING (SEGMENT_ID) ORDER BY SEGMENT_NAME;这个脚本的查询结果会分成两部分来自 DBA_ROLLBACK_SEGS 的表空间、状态等信息和来自 V$ROLLSTAT 的动态统计信息。如果你发现某一行 STATUS 不是 ONLINE那这行就要重点分析了。在自动 Undo 管理模式下正常情况下所有回滚段都应该是 ONLINE出现 OFFLINE 甚至 NEEDS RECOVERY就得立刻查告警日志和 trace 文件。V$ROLLSTAT 里的 XACTS 字段表示该回滚段当前活跃事务数EXTENTS 表示区数量WRITES 是累计写入字节数。这些字段是后续深度分析的基础数据巡检历史保留下来可以直接拿来趋势对比。2.2 深度检查回滚段扩展趋势与空间使用回滚段不是越大越好也不是越小越好。它的大小和扩展行为直接影响 DML 性能和 Undo 表空间的利用率。巡检过程中我喜欢把回滚段的当前大小、最大历史大小、扩展次数放在一起看遇到频繁扩展的回滚段就要留意了。SELECT R.SEGMENT_NAME, R.TABLESPACE_NAME, R.STATUS, S.OPTSIZE / 1024 / 1024 AS OPTIMAL_SIZE_MB, S.HWMSIZE / 1024 / 1024 AS HIGH_WATER_MARK_MB, S.SHRINKS, S.AVESHRINK / 1024 / 1024 AS AVG_SHRINK_MB, S.EXTENTS, S.RSSIZE / 1024 / 1024 AS CURRENT_SIZE_MB FROM DBA_ROLLBACK_SEGS R, V$ROLLSTAT S WHERE R.SEGMENT_ID S.SEGMENT_ID ORDER BY CURRENT_SIZE_MB DESC;这段 SQL 的关键在 V$ROLLSTAT 的几个统计字段。OPTSIZE 是回滚段的 OPTIMAL 大小在自动管理模式下的 Undo 表空间里这个值通常为 0不用太纠结HWMSIZE 是历史最高水位代表回滚段曾经扩展到多大SHRINKS 是回滚段发生收缩的次数如果这个数字反复增长说明回滚段在频繁扩展和收缩很可能是因为长事务或大事务导致空间分配抖动。看这个查询结果时一个简单的经验如果多个回滚段的 HIGH_WATER_MARK 都接近甚至超过 Undo 表空间的可用空间说明表空间容量可能不足如果有单个回滚段的 SHRINKS 数值明显大于其他段就值得查一查当时在跑什么业务了。2.3 竞争与热点检查找出被事务争用的回滚段回滚段的竞争问题在手动回滚段管理时代非常突出。如果使用 RBS 表空间且回滚段数量不足多个事务会争抢同一个回滚段出现等待事件。现在的自动 Undo 管理大幅缓解了这个问题但不代表完全不存在特别是某些特殊版本或异常的高并发场景下回滚段头块争用仍然可能发生。SELECT R.SEGMENT_NAME, S.GETS, S.WAITS, ROUND(S.WAITS / DECODE(S.GETS, 0, 1, S.GETS) * 100, 2) AS WAIT_RATE FROM DBA_ROLLBACK_SEGS R, V$ROLLSTAT S WHERE R.SEGMENT_ID S.SEGMENT_ID ORDER BY WAIT_RATE DESC;这个查询的 WAIT_RATE 字段表示等待率也就是回滚段头块访问发生等待的比例。这个值越小越好我一般以 1% 作为经验阈值。如果超过 1%就说明回滚段头块存在竞争可能需要通过扩容 Undo 表空间、调整回滚段数量来缓解。这个场景在自动管理模式下的 OLTP 库不太常见但是做巡检脚本时把这段保留着遇到性能问题可以用来排查总比临时上网翻脚本靠谱。3. 核心巡检 SQL 逐段深入解读3.1 一个脚本直接看全段状态、活跃事务、扩展行为和表空间余量前面几个脚本是分维度看的实际巡检时我会把它们整合成一个综合查询一条 SQL 出结果便于保存和对比。SELECT A.SEGMENT_NAME, A.TABLESPACE_NAME, A.STATUS, B.XACTS, B.EXTENTS, ROUND(B.RSSIZE / 1024 / 1024, 2) AS SIZE_MB, ROUND(B.HWMSIZE / 1024 / 1024, 2) AS HWM_MB, ROUND((C.BYTES - NVL(D.USED_BYTES, 0)) / 1024 / 1024, 2) AS FREE_MB, ROUND((C.BYTES - NVL(D.USED_BYTES, 0)) / C.BYTES * 100, 2) AS FREE_PCT FROM DBA_ROLLBACK_SEGS A, V$ROLLSTAT B, (SELECT TABLESPACE_NAME, SUM(BYTES) AS BYTES FROM DBA_DATA_FILES GROUP BY TABLESPACE_NAME) C, (SELECT TABLESPACE_NAME, SUM(BYTES) AS USED_BYTES FROM DBA_EXTENTS GROUP BY TABLESPACE_NAME) D WHERE A.SEGMENT_ID B.SEGMENT_ID AND A.TABLESPACE_NAME C.TABLESPACE_NAME AND A.TABLESPACE_NAME D.TABLESPACE_NAME ORDER BY A.STATUS, B.XACTS DESC;这个脚本把五个维度的信息合并到了一张结果集里回滚段名称、所在表空间、运行状态、当前活跃事务数、区数量、当前大小、历史高水位、表空间剩余空间和剩余百分比。一次巡检基础状态和容量风险一起看。FREE_PCT 字段我建议重点关注它是 Undo 表空间的空闲率。如果 FREE_PCT 长期低于 20%说明表空间随时可能因为空间不足触发 ORA-30036 错误这时就要考虑扩容了。脚本里用 DBA_EXTENTS 来统计使用量属于通用做法不会引入额外的权限要求。3.2 为什么状态字段不能只看“ONLINE”很多人巡检时只看 STATUS 是不是 ONLINE是 ONLINE 就觉得万事大吉。实际上这里有一个坑在自动 Undo 管理模式下回滚段状态字段显示 ONLINE 只能说明这个段处于在线可用状态并不能代表它的内部没有隐患。举个例子我曾经遇到一个案例所有回滚段都是 ONLINE但数据库频繁出现 ORA-01555 快照过旧。最后排查发现是因为 UNDO_RETENTION 设置的保留时间远大于 Undo 表空间实际能容纳的时间导致旧事务的读一致性镜像被覆盖。这个问题的根因和回滚段 STATUS 完全无关只看状态字段根本发现不了。所以脚本在设计时我特意同时查询了 Undo 表空间的剩余空间和历史高水位就是为了把“状态正常”和“容量足够”放在一起看。只有这两个方面都健康回滚段才能算真正的运行稳定。3.3 历史回滚段大小查询定位曾经的异常扩展有时候我们希望知道某个时间段内回滚段是否发生过异常增长。这可以通过 DBA_HIST_UNDOSTAT 这个 AWR 历史视图来实现。它记录了每十分钟粒度的 Undo 统计信息包括 Undo 表空间的已用空间、事务数量、快照过旧次数等。SELECT TO_CHAR(BEGIN_TIME, YYYY-MM-DD HH24:MI) AS BEGIN_TIME, UNDOBLKS, TXNCOUNT, MAXQUERLEN / 100 AS MAX_QUERY_LEN_S, MAXCONCURRENCY AS MAX_TXN_CONCURRENCY, UNXPSTEALCNT, EXPSTEALCNT FROM DBA_HIST_UNDOSTAT WHERE BEGIN_TIME SYSDATE - 7 ORDER BY BEGIN_TIME;这段脚本适合做定期归档比如每周跑一次把结果保存下来观察趋势。UNXPSTEALCNT 是未被过期区重用次数EXPSTEALCNT 是过期区被重用的次数这两个字段如果频繁增长说明 Undo 表空间长期处于高水位运行已经出现空间复用的压力。MAXQUERLEN 表示最长查询执行时间如果这个值经常超过 UNDO_RETENTION 的设置那么 ORA-01555 的风险就会显著上升。4. 巡检结果怎么看状态判定与处置策略4.1 一张表读懂回滚段状态字段回滚段的状态看起来就几个英文单词但不同状态对应的严重程度差别很大处置方式也完全不同。状态含义严重程度建议处置ONLINE回滚段在线正常使用中正常无需处理OFFLINE回滚段已离线不可用较高检查告警日志分析离线原因如为手动管理模式下需手工 ONLINEFULL回滚段已满高扩容 Undo 表空间或增加回滚段数量NEEDS RECOVERY回滚段损坏需要恢复严重需要结合备份恢复处理必要时重建 Undo 表空间PARTLY AVAILABLE部分可用多见于 RAC 环境高检查集群内实例状态确认回滚段归属实例是否正常UNDEFED回滚段处于未定义状态较低自动 Undo 模式下偶发观察即可手动模式下建议重建回滚段在自动 Undo 管理模式下正常情况下你只会看到 ONLINE 状态。一旦出现 OFFLINE 或 NEEDS RECOVERY别迟疑马上查 alert 日志和相关 trace定位具体原因。手动回滚段管理模式下OFFLINE 可能是手工操作的结果不一定是故障但你也得知道它为什么离线、是否有事务还在依赖它。4.2 结合 V$UNDOSTAT 判断容量与保留期的平衡脚本查完后如果发现 Undo 表空间使用率偏高下一步就要看 V$UNDOSTAT 来确定是不是保留期设置不合理。V$UNDOSTAT 是自动管理模式下的核心动态视图默认保留最近 10 分钟、每 10 秒采样一次的数据。一个实用的判断方法是比较两个指标当前 Undo 表空间能保留多长时间的镜像以及实际运行中最长查询的执行时间。如果单位时间内产生的 Undo 数据量是固定的而表空间容量只够保留 20 分钟但经常有查询需要跑 40 分钟那么 ORA-01555 就一定会出现。这种情况下有两个调整方向一是给 Undo 表空间扩容这是最直接的手段二是调低 UNDO_RETENTION 参数或启用 RETENTION GUARANTEE 策略让数据库在空间紧张时优先保留未过期的数据但这样做的风险是 DML 可能因为空间不足而报错需要业务侧接受这个代价。具体怎么选要看业务对查询一致性的容忍度。4.3 什么时候该扩容我的经验阈值控制回滚段巡检的成本关键在设定合理的阈值不要让每一次小波动都触发告警。根据我在不同业务量级数据库上的调试经验整理了几个参考阈值。Undo 表空间空闲率低于 20% 时进入观察名单连续两次巡检都低于 20% 就准备扩容空闲率低于 10%必须扩容或者立即排查是否有未提交的长事务。个别回滚段 XACTS 长期大于 10说明该段承载了大量活跃事务在自动管理下通常是表空间区分配不均可以观察整体分布。WAIT_RATE 超过 1%关注是否有回滚段头争用通常增加 Undo 表空间大小或调整数据文件分布可缓解。历史高水位 HWM 与当前表空间大小接近即将出现扩展瓶颈建议扩容。这里的核心原则是Undo 表空间不是越空越好太大会浪费存储太小会频繁触发告警和 ORA-30036关键是找到适合业务峰值的平衡点。5. 我在巡检中踩过的坑与排查案例5.1 ORA-01555 快照过旧脚本状态却一切正常这是我最想强调的一个案例。当时业务方反馈一个报表脚本频繁报 ORA-01555我第一时间跑了回滚段状态巡检脚本结果所有回滚段都是 ONLINEUndo 表空间还剩 30% 左右的空间表面看非常健康。后来深挖发现问题出在 UNDO_RETENTION 和最大查询耗时的矛盾上。报表脚本的最长执行时间大约在 1 小时左右但 Undo 表空间的实际保留能力只有 30 分钟两者之间存在严重不匹配。回滚段的状态确实正常但读一致性镜像的保留时间不够查询在回放旧数据时发现所需镜像已经被覆盖于是抛出 ORA-01555。从那以后我的巡检脚本里就固定增加了 DBA_HIST_UNDOSTAT 的查询并且要求每轮巡检都对比一次 MAX_QUERY_LEN 和 Undo 保留能力。这个坑告诉我回滚段状态巡检不能只看“状态”必须把容量、保留期和业务查询时长相绑定。5.2 回滚段状态偶发 OFFLINE差点误判为故障还有一次巡检脚本输出里有一个回滚段状态显示 OFFLINE当时第一反应是出故障了准备按应急预案处理。后来查了 V$PARAMETER 才发现这个库配置了多个 UNDO 表空间并且在 RAC 环境下不同实例各自管理自己的 Undo某个实例的回滚段在其他实例视角下显示为 OFFLINE 是正常现象。这个经历给了我一个教训巡检脚本的告警逻辑不能太僵硬。单实例环境下 OFFLINE 是异常RAC 环境下要先确认归属实例和集群状态再下结论。所以现在我处理巡检结果时会先把 INSTANCE_NUM 字段带出来遇到状态为 OFFLINE 的回滚段先确认它是否属于当前实例再决定是否拉起告警。5.3 巡检脚本的自动化落地建议脚本写好了剩下就是怎么让它持续发挥作用。我的建议是做一个简单的巡检任务每天凌晨 2 点执行一次综合查询结果追加到一张巡检历史表里保留 180 天。表结构可以按日期、回滚段名称、状态、大小、事务数、空闲率设计这样可以随时回溯某一天的回滚段状态。实现方式不复杂用 DBMS_SCHEDULER 创建一个每天执行一次的 JOB查询结果 INSERT 到历史表。异常判断可以放在 SQL 里做比如状态不等于 ONLINE 时输出告警标记。这样即使没有人每天去盯控制台输出异常也会被集中记录在案复盘时非常方便。6. 巡检频率与历史归档的几个实操细节6.1 不同业务场景下的巡检频率建议巡检频率不能一刀切。核心交易库和测试库对回滚段健康度的要求完全不同。根据我的运维经验核心 OLTP 库建议至少每天巡检一次大促或活动期间增加到每小时一次常规业务库可以每天一次每周做一次深度的历史趋势分析开发测试库可以把巡检频率放到每周一次但是在发布或批量数据操作前后要临时追加巡检。这里补充一个原则回滚段状态巡检是所有巡检项里成本最低的之一一条 SQL 查询不会对数据库产生明显负载。所以与其纠结频率高了会消耗性能不如把脚本优化到轻量然后用更频繁的巡检换来更早的故障发现。6.2 巡检输出怎么处理才不白做光跑脚本不归档等于白做。我是把每天的巡检输出统一存到一张历史表里再配合邮件或工单平台做异常通知。归档的好处在于当业务方忽然反馈某个 SQL 变慢、出现偶发报错时你可以迅速通过历史表反查当天的回滚段状态快速确认问题是否与 Undo 相关。如果公司有统一的监控平台也可以通过 SQL 把脚本输出推送到监控系统配置告警阈值。比如状态为 OFFLINE、空闲率低于 10%、WAIT_RATE 超过 1%都可以触发告警。把巡检从“人工定时看”变成“系统自动盯”才符合现代运维的基本要求。6.3 手动回滚段模式下的扩展建议如果你维护的确实是老库仍在使用手动回滚段管理那巡检脚本的价值会更高。手动模式下回滚段数量、每个段的大小、OPTIMAL 参数的设置都需要 DBA 手工维护。巡检时如果发现某个回滚段频繁扩展和收缩可以考虑通过 ALTER ROLLBACK SEGMENT 调整 OPTIMAL 大小减少空间分配抖动如果发现部分回滚段长期没有事务使用也可以把它们设为 OFFLINE释放资源给其他段。自动 Undo 管理模式下的巡检相对省心但也不能完全不看。就像前面说的自动管理只负责“干活”不负责“报警”巡检的价值在于用低成本的方式发现潜在趋势避免故障真的发生。我在实际维护中最大的体会是回滚段巡检最大的敌人不是脚本不够强而是侥幸心理。状态字段全是 ONLINE不代表一切太平把容量、趋势、竞争、事务分布综合起来看才能给回滚段的运行状态下一个准确结论。把这套脚本纳入日常巡检计划历史数据保留下来半年之后你再回头看会发现它帮你在故障爆发前拦下了不少风险。