ORA-30036错误表明UNDO表空间物理空间耗尽或被长事务锁死,需立即验证:查DBA_TABLESPACE_USAGE_METRICS确认used_percent≥95%即空间告急;关联V$TRANSACTION与V$SESSION识别USED_UBLK>10000且START_TIME超30分钟的长事务;优先添加新数据文件扩容,慎用MAXSIZE UNLIMITED;批量DML须分批提交,避免单事务UNDO暴涨。
ORA-30036 错误出现时,说明当前撤销(UNDO)表空间已无法为新事务分配回滚段,事务直接失败。这不是“稍等就能恢复”的临时抖动,而是资源硬性耗尽,必须立刻干预。
怎么快速确认是 UNDO 表空间真满了
别只看错误就急着扩容。先验证是否真的满,还是被长事务锁死:
-
V$UNDOSTAT中的UNDOBLKS和MAXQUERYLEN能反映最近 1 小时内 UNDO 消耗趋势和最长查询时间,但不等于当前占用 - 真正要看的是
DBA_TABLESPACE_USAGE_METRICS视图:运行SELECT tablespace_name, used_percent FROM dba_tablespace_usage_metrics WHERE tablespace_name = 'UNDOTBS1';—— 若used_percent≥ 95%,基本可判定物理空间告急 - 更关键的是查
V$TRANSACTION+V$SESSION关联:是否存在USED_UBLK> 10000 且START_TIME超过 30 分钟的事务?这类事务会持续占用 UNDO 块,导致空间无法复用
加数据文件比调 UNDO_RETENTION 更直接有效
UNDO_RETENTION 是“保留时间建议值”,不是强制锁定期。当空间紧张时,Oracle 仍会覆盖旧 UNDO 数据——所以单纯调大这个参数治标不治本。
实操上优先执行扩容:
- 添加新数据文件最安全:
ALTER TABLESPACE UNDOTBS1 ADD DATAFILE '/u01/oradata/yourdb/undotbs02.dbf' SIZE 2G AUTOEXTEND ON NEXT 100M MAXSIZE UNLIMITED; - 如果磁盘空间受限,只能扩现有文件:先确认它支持自动扩展(查
DBA_DATA_FILES的AUTOEXTENSIBLE列),再执行ALTER DATABASE DATAFILE '/u01/oradata/yourdb/undotbs01.dbf' AUTOEXTEND ON NEXT 200M MAXSIZE 4G; - 注意:新增文件路径需有写权限,且 Oracle 用户能访问;
MAXSIZE UNLIMITED在生产环境慎用,建议设合理上限(如 8G),避免填满磁盘
批量 DML 必须分事务提交,否则 UNDO 压力翻倍
一条 UPDATE 影响 50 万行,UNDO 不是按“行”存,而是按“块变更前镜像”存。全在一个事务里提交,UNDO 瞬间暴涨,极易触发 ORA-30036。
正确做法是显式分批:
- 用
FORALL ... SAVE EXCEPTIONS或 PL/SQL 循环 +COMMIT控制粒度,例如每 5000 行COMMIT一次 - 避免在存储过程中隐式开启大事务:检查是否有未
COMMIT/ROLLBACK的异常分支,或PRAGMA AUTONOMOUS_TRANSACTION被误用 - DDL 操作(如
CREATE INDEX)本身不走 UNDO,但其附带的排序、建位图索引等阶段会大量使用 TEMP 表空间——别混淆 UNDO 和 TEMP,它们是两套机制
切换 UNDO 表空间要停业务吗
不需要停库,但存在极短窗口期(秒级)所有新事务会排队等待切换完成。风险点在于:旧 UNDO 表空间不能立即删,必须等其中所有事务彻底结束。
操作顺序不能错:
- 先创建新 UNDO 表空间:
CREATE UNDO TABLESPACE UNDOTBS2 DATAFILE '/u01/oradata/yourdb/undotbs03.dbf' SIZE 4G; - 再切换:
ALTER SYSTEM SET undo_tablespace = UNDOTBS2 SCOPE=BOTH;—— 此刻新事务开始用 UNDOTBS2,旧事务仍在 UNDOTBS1 上跑完 - 观察
V$ROLLSTAT中UNDOTBS1对应的EXTENTS是否持续下降,直到为 0;再查DBA_ROLLBACK_SEGS确认所有回滚段状态为OFFLINE - 最后才执行
DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS AND DATAFILES;—— 提前删会报ORA-01548
真正容易被忽略的是:应用连接池里的长连接可能缓存了旧事务上下文,切换后首次执行仍可能报错,建议滚动重启应用服务。


















