调高UNDO_RETENTION不能防止事务段争用,反而可能加剧;争用根源是回滚段头锁竞争或区分配瓶颈。查V$UNDOSTAT.MAXCONCURRENCY≥20或频繁达50+为争用信号,结合UNDOBLKS与TXNCOUNT增速比识别长事务;重点排查V$SESSION中INACTIVE长会话并kill;调整前须确保EXPIRED空间充足,治本顺序:杀长会话→等EXPIRED回升→按MAXQUERYLEN*1.5微调UNDO_RETENTION并启用RETENTION GUARANTEE。

调高 UNDO_RETENTION 不能防止事务段争用,反而可能加剧它——争用根源是回滚段头(rollback segment header)锁竞争或区分配瓶颈,不是保留时间短。
查 V$UNDOSTAT.MAXCONCURRENCY 判断是否真有争用
事务段争用的直接信号不是报错,而是 MAXCONCURRENCY 持续 ≥ 20 或频繁跳到 50+。这个值代表同一时刻争抢回滚段头/区分配锁的事务数。
- 执行
SELECT BEGIN_TIME, MAXCONCURRENCY, UNDOBLKS, TXNCOUNT FROM V$UNDOSTAT ORDER BY BEGIN_TIME DESC FETCH FIRST 20 ROWS ONLY - 若某时段
MAXCONCURRENCY高企,且UNDOBLKS增速远超TXNCOUNT(比如事务数+100%,Undo块+400%),说明存在长事务或未提交事务卡住空间分配 - 注意:
UNDOBLKS是数据库块数(通常 8KB),不是字节数,别误算成 MB
别只看 V$TRANSACTION,重点抓 V$SESSION 中的 INACTIVE 长会话
很多“长事务”其实是应用连接池没设超时,SQL 执行完但连接挂着不提交,V$TRANSACTION 里能看到 START_TIME,但 V$SESSION.STATUS 是 INACTIVE、SQL_ID 为空。
- 查疑似空闲长事务:
SELECT sid, serial#, username, status, sql_id, prev_sql_id, last_call_et/60 mins_idle FROM v$session WHERE status = 'INACTIVE' AND last_call_et > 1800 ORDER BY last_call_et DESC FETCH FIRST 5 ROWS ONLY - 对命中会话,用
SELECT sql_text FROM v$sql WHERE sql_id IN ('&prev_sql_id')反查上一条执行语句,确认是否 DELETE/UPDATE 大量数据后没提交 - 这类会话必须 kill:
ALTER SYSTEM KILL SESSION '&sid,&serial#',否则它们持续占用回滚段头,阻塞新事务分配
调整 UNDO_RETENTION 前先确认空间是否撑得住
盲目调高 UNDO_RETENTION 会让 UNEXPIRED 区块堆积,进一步挤压 EXPIRED 空间,导致新事务无法获得新区段——这不是参数问题,是空间失衡。
- 查状态分布:
SELECT STATUS, SUM(BLOCKS) BLOCKS_CNT FROM DBA_UNDO_EXTENTS WHERE TABLESPACE_NAME = 'UNDOTBS1' GROUP BY STATUS(替换为你的表空间名) - 若
ACTIVE + UNEXPIRED占比 > 90%,且EXPIRED接近 0,优先清理长事务,而不是扩容或调参 - 检查自动扩展:
SELECT file_name, autoextensible, maxbytes/1024/1024 AS max_mb FROM dba_data_files WHERE tablespace_name = 'UNDOTBS1';若AUTOEXTENSIBLE = NO且已近满,调任何参数都无效
真正治本的操作顺序是:先杀掉 INACTIVE 长会话 → 再确认 DBA_UNDO_EXTENTS 中 EXPIRED 比例回升 → 最后根据 V$UNDOSTAT.MAXQUERYLEN 的 1.5 倍微调 UNDO_RETENTION 并启用 RETENTION GUARANTEE。绕过前两步直接改参数,等于在堵漏的水管上贴胶带。


















