Undo压力真凶常藏于ON CPU状态下的递归操作而非log file sync事件,需结合v$transaction查used_ublk>10000的长事务、DBA_UNDO_EXTENTS验证回收能力,并排查INACTIVE会话中last_call_et>300且未rollback的残留事务。

ASH本身不记录“谁在写Undo”,因为Undo写入由后台进程(如ora_dbw0_*)完成,前台会话采样时通常只显示ON CPU或极短的log file sync,直接查event或sql_id会漏掉真凶。
为什么不能只查 EVENT = 'log file sync' 或 sql_id 对应的业务语句
Undo压力不是来自单次DML提交,而是来自高频率的回滚段维护操作——比如索引分裂、undo header更新、事务表扩展。这些动作触发大量递归SQL,在ASH中表现为:
-
session_state = 'ON CPU',但sql_id是0000000000000000或系统内部语句(如select /*+ rule */ from sys.undo$) -
sql_opname IN ('INSERT', 'UPDATE', 'DELETE', 'DDL'),且event为空或为NULL -
program或module字段暴露源头(例如module = 'BatchDelete'却持续出现ON CPU样本)
必须关联 v$transaction 找出真实占用者
ASH只是1秒一次的快照,一个长时间未提交的事务可能只留下几条样本,但它持续占用Undo段。真正高风险的是used_ublk > 10000(即>80MB)的事务。
立即执行:
SELECT s.sid, s.serial#, s.username, s.program, t.used_ublk, t.start_time FROM v$session s JOIN v$transaction t ON s.taddr = t.addr ORDER BY t.used_ublk DESC FETCH FIRST 5 ROWS ONLY;
-
used_ublk单位是数据库块(默认8KB),>10000 ≈ >80MB,属紧急级别 - 若
username为空但program类似oracle@host (J000),说明是JOB进程在跑未提交批量操作 -
status = 'INACTIVE'的会话要重点盯:它可能已断连,但事务仍持锁并占Undo
用 DBA_UNDO_EXTENTS 和 V$UNDOSTAT 交叉验证Undo是否卡住
光看会话和事务不够,得确认Undo表空间本身是否健康。关键指标不是“用了多少”,而是“能不能及时回收”:
- 查
DBA_UNDO_EXTENTS中STATUS = 'EXPIRED'占比是否过低( - 查
V$UNDOSTAT中MAXCONCURRENCY是否持续>10,表示并发事务争抢Undo段头 - 观察
UNDOBLKS/TXNCOUNT比值是否异常升高:同一事务写入Undo块数激增,常因大字段更新或LOB操作引发
最易被忽略的一点:Undo压力往往藏在“已提交但未释放”的事务残留里——比如应用层捕获了异常却没显式rollback,或PL/SQL中EXCEPTION块遗漏了ROLLBACK。这类事务不会出现在v$transaction中,但会拖慢整个Undo回收链。此时必须结合V$SESSION的prev_sql_id和last_call_et,排查那些status = 'INACTIVE'但last_call_et > 300(5分钟)的会话。


















