Undo争用本质是事务调度卡在分配锁而非空间不足,根因是RAC中多实例争抢Undo段头latch/lock;须确保各实例独占Undo表空间、合理设置undo_retention、禁用_undo_autotune,并通过DBA_UNDO_EXTENTS中EXPIRED占比诊断回收阻塞。
Undo争用不是空间不够,而是事务调度卡在分配锁上
oracle rac中出现“undo表空间满”或enq: us - contention等待,90%以上不是因为磁盘空间真耗尽,而是多个实例同时抢同一个undo段头(segment header)或区(extent)的分配权。本质是并发事务在争抢回滚段元数据结构的latch/lock,不是数据块写不进去了。
典型现象包括:V$UNDOSTAT.MAXCONCURRENCY持续≥20、UNDOBLKS增速远超TXNCOUNT(比如事务+1倍,Undo块+4倍)、DBA_UNDO_EXTENTS中STATUS = 'EXPIRED'占比低于20%。
- 别一看到“UNDOTBS1使用率95%”就加数据文件——可能99%的空间是
UNEXPIRED状态,根本不能重用 - 查
V$TRANSACTION.START_TIME没用:很多“长事务”其实是V$SESSION.STATUS = 'INACTIVE'且SQL_ID为空的空闲连接挂着未提交 -
undo_retention设成86400(24小时)又没开AUTOEXTEND,Oracle不敢回收,只会把空间锁死
RAC必须每个实例独占Undo表空间,共享等于埋雷
RAC下UNDO_TABLESPACE参数必须为每个实例指定不同值,比如节点1用UNDOTBS1,节点2用UNDOTBS2。共用同一个Undo表空间会破坏事务可见性规则,直接触发ORA-01555快照过旧错误,这不是性能问题,是数据一致性风险。
实操验证命令:SHOW PARAMETER undo_tablespace,确保各节点返回值不同;再查DBA_DATA_FILES确认两个表空间物理路径不交叉。
- 大小不能拍脑袋填:按峰值估算——
每秒最大DML事务数 × 平均事务Undo块数 × 1.5(预留),而不是统一塞100G - 数据文件必须放在独立高速磁盘上,严禁与Redo日志共盘——RAC中Redo已通过私网广播放大IO压力,再叠加Undo争用就是雪上加霜
- 禁用
_undo_autotune:Oracle 12c+默认开启,它会根据最长查询时间动态拉长undo_retention,导致空间被长期锁定;执行ALTER SYSTEM SET "_undo_autotune" = FALSE SCOPE=SPFILE并重启
Undo争用常是其他层问题的反射,别只盯着表空间
很多所谓“Undo争用”实际根子在应用或索引设计:序列生成ID单调递增、索引前导列是created_date、表没启ASSM还用FREELISTS……这些都会制造热块,迫使跨实例一致性读,间接放大Undo远程访问压力。
例如:DBA_SEQUENCES.ORDER_FLAG = 'Y'或CACHE_SIZE < 100,会导致所有INSERT挤在同一个索引叶块,引发gc buffer busy acquire,Undo只是背锅侠。
- 高并发INSERT慎用
/*+ APPEND */:RAC下强制走LOCAL临时段,新数据全堆在当前节点,制造本地Undo热点 - 分区表务必用
GLOBAL INDEX?错——RAC中它是单点瓶颈,每次DML都要协调全局锁,Undo段只是表象 - 检查
V$SYSTEM_EVENT里log file sync是否异常高:频繁小事务(如循环单条INSERT)会拖慢提交,让Undo释放变慢,加剧争用
查EXPIRED占比比看“使用率”有用十倍
表空间使用率99%≠真没空间了。关键看DBA_UNDO_EXTENTS中STATUS分布:EXPIRED占比应稳定在30%~60%,低于20%说明回收机制被阻塞,高于70%说明undo_retention可能设得太短,频繁覆盖影响闪回查询。
执行这个SQL: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设得过长又没开AUTOEXTEND,调低比加文件更治本 - 别误算
UNDOBLKS单位:它是数据库块(通常8KB),不是字节,别当成MB直接除1024
真实场景里,Undo争用最麻烦的不是配置多难,而是它总藏在别的问题后面——你调大undo_retention,可能只是把一个未提交的应用连接问题,从报错变成静默卡顿。


















