undo表空间使用率高主因是tuned_undoretention被自动调优异常拉高,致大量unexpired区段无法回收;应查v$undostat趋势及dba_undo_extents状态分布,关闭\_undo_autotune并重设undo_retention。

查 v$undostat 看真实压力趋势,别只盯 DBA_DATA_FILES 的占用率
95% 使用率不等于空间真没了,更可能是 tuned_undoretention 被自动拉高,导致大量 UNEXPIRED 区段卡住不回收。直接扩容或切表空间往往几分钟后又涨满。
-
NOSPACEERRCNT > 0→ 已发生ORA-30036,必须立刻干预 -
MAXQUERYLEN持续大于你设的undo_retention→ 长查询强制锁住旧版本,undo 无法释放 -
UNDOBLKS高 +TXNCOUNT低 → 单个事务极大(比如未分批的全表DELETE) - 执行这句快速看最近 10 条趋势:
SELECT BEGIN_TIME, UNDOBLKS, TXNCOUNT, MAXQUERYLEN, NOSPACEERRCNT FROM v$undostat ORDER BY BEGIN_TIME DESC FETCH FIRST 10 ROWS ONLY;
用 dba_undo_extents 分清 ACTIVE/UNEXPIRED/EXPIRED 占比
不同状态代表完全不同的处理路径。直接杀会话或删文件前,先确认当前空间到底被谁“占着”。
-
ACTIVE占比高 → 有长事务未提交,查v$transaction和关联v$session -
UNEXPIRED远高于EXPIRED(比如 >80%)→ 典型的_undo_autotune=true失控,不是配置低,是机制反向起作用 -
EXPIRED已占多数但空间不释放 → 检查数据文件是否启用AUTOEXTEND,或表空间被隐式锁定 - 执行这句查分布:
SELECT status, COUNT(*) cnt, ROUND(SUM(bytes)/1024/1024, 2) mb FROM dba_undo_extents WHERE tablespace_name = (SELECT UPPER(value) FROM v$parameter WHERE name = 'undo_tablespace') GROUP BY status ORDER BY status;
关掉 _undo_autotune 并重设 undo_retention 是最稳的生产操作
Oracle 10.2+ 默认开启该隐藏参数,它会无视你手动设的 undo_retention,按负载动态推高保留时间——尤其在非自动扩展的数据文件上,tuned_undoretention 可能被拉到几小时甚至一天,和业务实际需求脱钩。
- 先确认是否生效:
SELECT MAX(tuned_undoretention) max_tuned, MAX(maxquerylen) max_query_sec FROM v$undostat WHERE begin_time > SYSDATE - 1;
-
max_tuned超过 86400(24 小时)且max_query_sec很小 → 基本可断定是自动调优 bug - 执行关闭并重设(建议从 3600 秒起步):
ALTER SYSTEM SET "_undo_autotune" = FALSE SCOPE=BOTH;<br>ALTER SYSTEM SET undo_retention = 3600 SCOPE=BOTH;
- 注意:改完不会立即释放空间,需等待现有
UNEXPIRED区段按新 retention 自然过期
查 v$transaction 找出真正在“吃” undo 的会话,别只看 v$session 状态
很多 DBA 直接切表空间,结果新表空间几分钟后也涨满——因为同一个长事务还在跑。关键字段是 used_ublk 和 idle_mins,不是 status = 'ACTIVE' 就代表有问题。
-
idle_mins > 5且used_ublk > 10000→ 极可能挂起(应用忘记COMMIT或被阻塞) -
username是业务账号(非SYSTEM/DBA)→ 找对应开发确认逻辑 -
osuser/machine指向某台应用服务器 → 可临时重启该连接池,而非杀会话 - 必须关联
v$session查来源:SELECT s.sid, s.serial#, s.username, s.osuser, s.machine, t.start_time, t.used_ublk, (SYSDATE - t.start_time) * 24 * 60 idle_mins FROM v$transaction t JOIN v$session s ON s.taddr = t.addr ORDER BY t.start_time;
真正难处理的不是空间本身,而是那些没显式报错、却让 tuned_undoretention 在后台悄悄爬升到数万秒的隐式长事务——它们藏在 RAC 节点间差异里,藏在应用连接池复用中,也藏在 DBA 只查 DBA_DATA_FILES 的惯性里。











