undo段争用本质是事务行为、保留策略与实例隔离失配导致的调度卡顿,非空间不足;盲目扩容或调高undo_retention会加剧问题。
直接结论:undo段争用不是空间不够的问题,而是事务行为、保留策略和实例隔离三者失配导致的资源调度卡顿。盲目扩文件或调高 undo_retention 通常会让问题更糟。
查清争用是否真来自Undo段,还是被误判的长事务
很多“Undo争用”其实是未提交事务卡住空间,而非Undo段本身不足。关键看 V$UNDOSTAT 中的两个指标是否同步异常:
-
MAXCONCURRENCY持续 ≥ 20,且对应时段UNDOBLKS增速远超TXNCOUNT(比如事务数+2倍,Undo块+5倍)→ 极可能有长事务或空闲连接挂着未提交 -
DBA_UNDO_EXTENTS中STATUS = 'EXPIRED'占比低于 20% → 不是空间小,而是回收机制被阻塞;此时UNDO_RETENTION很可能设得过长(如 86400),又没开AUTOEXTEND,Oracle 不敢重用 - 别只信
V$TRANSACTION.START_TIME:INACTIVE状态但SQL_ID为空的会话,才是真正的“幽灵事务”,必须联合V$SESSION查status和last_call_et
禁用 _undo_autotune 是最有效的第一刀
Oracle 12c+ 默认开启自动调优,它会根据最长查询时间动态拉长 UNDO_RETENTION,导致空间被长期锁定。这不是优化,是假性耗尽:
- 执行
ALTER SYSTEM SET "_undo_autotune" = FALSE SCOPE=SPFILE,重启生效 - 随后设一个合理静态值:
undo_retention应略大于V$UNDOSTAT.MAXQUERYLEN的峰值(比如最大 1200 秒,就设 1800) - 禁止设 > 3600 —— 超过一小时基本无业务意义,只会让
UNEXPIRED区块堆积,触发enq: US - contention
RAC中Undo表空间必须实例独占,且不能共享
共享Undo会导致事务可见性错乱和 ORA-01555,这是RAC硬性规则,不是建议:
- 每个实例必须有独立的Undo表空间:
SHOW PARAMETER undo_tablespace必须返回不同值(如UNDOTBS1、UNDOTBS2) - 大小按峰值估算:每秒最大DML事务数 × 平均事务Undo块数 × 1.5(预留),而不是拍脑袋填 100G
- 数据文件必须放在独立高速磁盘上,严禁与Redo日志共盘——RAC中Redo写入已通过私网广播放大IO压力,再叠加Undo争用就是雪上加霜
避免Undo争用被其他层问题放大
Undo争用常是表象,根子可能在应用或索引设计:
- 检查
dba_sequences:若order_flag = 'Y'或cache_size ,序列生成ID单调递增,导致索引叶块热块 → 触发跨实例一致性读,间接放大Undo远程访问压力 - 高并发INSERT时慎用
/*+ APPEND */:RAC下它强制走LOCAL临时段,新数据全堆在当前节点,制造本地Undo热点,反而加剧争用 - 分区表务必用
LOCAL INDEX:GLOBAL索引在RAC中是单点瓶颈,每次DML都要协调全局锁,Undo段只是背锅侠
真正难处理的是那些不报错、不hang、但持续拖慢吞吐的隐性争用——它们藏在 UNEXPIRED 区块里,靠监控看不见,只在AWR尖峰时刻露头。这时候,关掉自动调优、砍掉过长保留、确认实例隔离,三步做完,往往比扩容快十倍。











