<p>ASH 中直接反映 UNDO 争用的字段是 event(含 'enq: US - contention' 或 'undo segment extension')和 wait_class(为 Configuration 或 System I/O),并需结合 session_id、sql_id、current_obj#、p1text/p1(p1=undo segment#)分析。</p>

ASH 中哪些字段能直接反映 UNDO 争用
UNDO 争用在 ASH 中最直接的信号是 event 列出现 enq: US - contention 或 undo segment extension,同时 wait_class 为 Configuration 或 System I/O。注意:enq: US - contention 表示多个会话在争抢同一个 UNDO 段头(US = Undo Segment),不是普通锁等待;而 undo segment extension 出现频繁,说明 UNDO 表空间自动扩展太勤或初始设置过小。
关键关联字段必须查:session_id、sql_id、current_obj#(若为 -1 通常指向 UNDO 表空间本身)、p1text/p1(对 enq: US - contention,p1 是 undo segment#)。
如何用 ASH 快速定位争用最严重的 UNDO 段
不要只看单条 ASH 记录,要聚合分析。核心思路是:按 p1(即 undo segment#)分组统计等待次数和时间,并关联 dba_rollback_segs 查段名。
SELECT r.segment_name, COUNT(*) waits, SUM(time_waited) time_ms FROM v$active_session_history a JOIN dba_rollback_segs r ON a.p1 = r.segment_id WHERE a.event = 'enq: US - contention' AND a.sample_time > SYSDATE - 1/24 -- 近1小时 GROUP BY r.segment_name ORDER BY time_ms DESC;
- 如果某段(如
UNDOTBS1)占比远超其他段,说明该 UNDO 表空间内段分布不均,可能因段数不足或自动管理未启用 -
segment_id和dba_rollback_segs.segment_id是严格对应的,但注意:Oracle 12c+ 默认使用自动段管理(ASSM)的 UNDO 表空间,此时dba_rollback_segs中的段名只是逻辑别名,真实段由 Oracle 动态分配 - 若查询无结果,确认是否启用了
UNDO_MANAGEMENT=AUTO(非 MANUAL),否则 ASH 不会记录 US 类事件
为什么查到 SQL_ID 后仍难复现问题
因为 sql_id 只代表“当时正在执行的语句”,但 UNDO 争用往往源于该语句产生的大量 UNDO 数据 + 长事务 + 其他会话并发提交/回滚——真正瓶颈常不在 SQL 本身,而在事务生命周期管理。
需交叉验证以下三点:
- 查该
sql_id对应的v$sql中elapsed_time和undo_change#是否异常高(后者需开启STATISTICS_LEVEL=ALL) - 用
v$transaction看是否存在start_time很早但used_ublk持续增长的事务 - 检查
v$undostat的maxquerylen(秒)和unxpstealcnt(非过期块被偷用次数):若后者 > 0,说明 UNDO 回收压力大,可能触发争用
UNDO 争用容易被误判成别的问题
常见混淆点:把 enq: US - contention 当作普通锁冲突去查 v$lock,或当成 I/O 问题去查磁盘延迟。其实它本质是内存结构(UNDO 段头 buffer)的 latch-like 争抢,跟磁盘无关。
典型误操作包括:
- 看到
wait_class = System I/O就优化存储,实际可能是undo segment extension触发的临时文件写入,根源仍是 UNDO 表空间配置不当 - 用
DBA_HIST_ACTIVE_SESS_HISTORY替代V$ACTIVE_SESSION_HISTORY查实时争用——历史视图采样间隔默认 10 秒,可能漏掉尖峰 - 忽略数据库版本差异:Oracle 19c 后引入
_undo_autotune参数,默认开启,会动态调整 UNDO_RETENTION,但若应用依赖固定 retention 值,反而加剧段切换争用
UNDO 争用真正的复杂点在于:它既不是纯 SQL 问题,也不是纯配置问题,而是事务行为、UNDO 空间管理策略、实例参数三者耦合的结果。单独调大 UNDO_TABLESPACE 大小或延长 UNDO_RETENTION,不解决段头争抢;只优化 SQL,也压不住长事务的 UNDO 泄露。得从 ASH 找出“谁在哪个段上卡住”,再回到业务逻辑里看事务边界是否合理。


















