应查V$UNDOSTAT看历史压力趋势,重点关注NOSPACEERRCNT是否大于0、MAXQUERYLEN是否持续超UNDO_RETENTION,结合UNDOBLKS与TXNCOUNT比值识别大事务;再查DBA_UNDO_EXTENTS状态分布及v$transaction中used_ublk高且idle_mins长的会话。

查 v$undostat 看历史压力趋势,别只盯当前占用率
DBA_DATA_FILES 显示 UNDOTBS1 占用 98%,这数字本身没意义——可能只是“被占着”,但未必真缺空间。关键要看 v$undostat 里过去几小时的真实压力:如果 NOSPACEERRCNT > 0,说明已发生过 ORA-30036;如果 MAXQUERYLEN 持续大于你设的 UNDO_RETENTION,说明有长查询锁死了旧版本,undo 无法回收。
执行这条语句快速抓最近 10 条记录:
SELECT BEGIN_TIME, UNDOBLKS, TXNCOUNT, MAXQUERYLEN, NOSPACEERRCNT FROM v$undostat ORDER BY BEGIN_TIME DESC FETCH FIRST 10 ROWS ONLY;
-
UNDOBLKS高 +TXNCOUNT低 → 单个事务极大(比如未分批的全表 DELETE) -
NOSPACEERRCNT = 0且MAXQUERYLEN → 大概率是长事务没提交,不是配置问题 - 注意
v$undostat默认只保留 4 天,别查太早的历史
定位正在吃 UNDO 的活跃事务
很多 DBA 直接扩容或切表空间,结果几分钟后新表空间也涨满——因为同一个长事务还在跑。真正该杀的是它。
重点看这几个字段:
SELECT s.sid, s.serial#, s.username, s.osuser, s.machine,
t.used_ublk, t.start_time,
(SYSDATE - t.start_time) * 24 * 60 idle_mins
FROM v$transaction t
JOIN v$session s ON s.taddr = t.ses_addr
ORDER BY t.start_time;
-
used_ublk > 10000且idle_mins > 5→ 极可能挂起(应用忘记 COMMIT 或被阻塞) -
username是业务账号(非 SYSTEM/DBA)→ 找对应开发确认逻辑 -
osuser/machine指向某台应用服务器 → 可临时重启该连接池,比直接ALTER SYSTEM KILL SESSION更安全
小心 _undo_autotune 自动调优反向加压
Oracle 10.2+ 默认开启 _undo_autotune=true,它会无视你手动设的 undo_retention,按负载动态拉高保留时间。尤其当 undo 表空间没开 autoextend 时,为防 ORA-01555,它可能把 tuned_undoretention 推到几小时甚至一天。
查当前是否生效:
SELECT tuned_undoretention FROM v$undostat WHERE rownum = 1;
- 如果返回值远高于你设的
undo_retention,且磁盘紧张,可关掉:ALTER SYSTEM SET "_undo_autotune"=FALSE SCOPE=BOTH; - 关之前先确认
v$undostat中NOSPACEERRCNT是否为 0,避免关闭后引发快照过旧 - 这个参数是隐藏参数,
SCOPE=BOTH生效需实例重启才完全落地,临时缓解可用
检查 DBA_UNDO_EXTENTS 状态分布
DBA_UNDO_EXTENTS 的 STATUS 列能告诉你 undo 空间为什么“不释放”:是真被占着(ACTIVE),还是卡在“未过期”状态(UNEXPIRED)动不了。
执行:
SELECT status, COUNT(*) Num_Extents,
ROUND(SUM(bytes)/1024/1024, 2) MB
FROM dba_undo_extents
GROUP BY status
ORDER BY status;
-
ACTIVE高 → 有大量未提交事务,优先查v$transaction -
UNEXPIRED高 +EXPIRED低 →_undo_autotune或UNDO_RETENTION设置过高,undo 被强制留着 -
EXPIRED高 → 空间其实可重用,但文件物理上不会自动 shrink,这是正常行为
真实难点不在 SQL 怎么写,而在于 v$transaction 里那个 used_ublk 两万、idle_mins 二十分钟的会话,背后连着哪段 Java 代码、哪个 RPC 调用、有没有 Spring 的 @Transactional 套在 Controller 上——这些,数据库看不到,但 undo 记得清清楚楚。











