ora-01555 的根本原因是 undo 表空间物理空间不足,而非 undo_retention 参数设置过小;oracle 在空间紧张时会强制覆盖未过期的 undo 块,因此应优先检查 undo 表空间是否自动扩展及实际使用率是否长期低于5%。
ora-01555 不是因为 undo_retention 没设够,而是它根本没被遵守——空间不够时,oracle 会直接覆盖未过期的 undo 块。
查清楚是不是真缺空间,而不是参数太小
很多人一见 ORA-01555 就调大 UNDO_RETENTION,结果问题照旧。真正该先看的是 undo 表空间有没有余地撑住当前负载。
- 运行
SELECT file_name, autoextensible, maxbytes/1024/1024 AS max_mb FROM dba_data_files WHERE tablespace_name = (SELECT value FROM v$parameter WHERE name = 'undo_tablespace');,确认AUTOEXTENSIBLE是YES - 查真实使用率:
SELECT tablespace_name, ROUND((free_space/total_space)*100, 2) pct_free FROM (SELECT tablespace_name, SUM(bytes) total_space FROM dba_data_files GROUP BY tablespace_name), (SELECT tablespace_name, SUM(bytes) free_space FROM dba_free_space GROUP BY tablespace_name) WHERE total_space.tablespace_name = free_space.tablespace_name AND tablespace_name = (SELECT value FROM v$parameter WHERE name = 'undo_tablespace'); - 如果
pct_free长期低于 5%,且AUTOEXTENSIBLE = NO,那所有参数调整都是白忙——先扩容或开自动扩展
为什么调高 UNDO_RETENTION 反而让问题更糟
UNDO_RETENTION 是“建议值”,不是承诺。当 undo 表空间吃紧,Oracle 会优先回收 UNEXPIRED 状态的块(即已提交但还没到保留时间的块),哪怕你设了 7200 秒。
- 盲目把
UNDO_RETENTION从 900 调到 3600,若表空间无自动扩展,会导致活跃 undo 堆积更快,NOSPACEERRCNT在V$UNDOSTAT中飙升 -
V$UNDOSTAT.MAXQUERYLEN才是关键参考:它反映最近 10 秒采样窗口内最长查询耗时(秒)。若该值持续大于当前UNDO_RETENTION,说明参数已失效 - 用
SELECT begin_time, end_time, undoblks, txncount, ssolderrcnt, nospaceerrcnt FROM v$undostat WHERE begin_time > SYSDATE - 1/24 ORDER BY begin_time DESC;定位到分钟级压力突增点,比看 AWR 更准
怎么设一个靠谱的 UNDO_RETENTION 值
设太高浪费空间,设太低白设。合理值不是拍脑袋,而是基于最长业务查询 + 空间承载能力反推。
- 先查系统里最慢的活跃查询:
SELECT sid, serial#, username, sql_id, ROUND(elapsed_seconds/60, 1) mins FROM v$session WHERE status = 'ACTIVE' AND sql_id IS NOT NULL ORDER BY elapsed_seconds DESC FETCH FIRST 3 ROWS ONLY; - 再反查 SQL 文本:
SELECT sql_text FROM v$sql WHERE sql_id = '<sql_id>';</sql_id>,确认是不是报表、导出或 ETL 类长任务 - 取这些查询典型耗时的 1.5 倍作为目标值,例如最长稳定在 1800 秒(30 分钟),则设
UNDO_RETENTION = 2700 - 但必须同步验证 undo 表空间能否撑住:所需空间 ≈
UNDO_BLOCK_PER_SEC × MAXQUERYLEN × DB_BLOCK_SIZE;其中UNDO_BLOCK_PER_SEC可从V$UNDOSTAT算出:SELECT MAX(undoblks / ((end_time - begin_time) * 24 * 3600)) FROM v$undostat;
数据泵/ETL 场景下,调参不如切分
expdp、OMS、DWS 迁移报 ORA-01555,八成不是 undo 不够,而是单次扫描耗时远超 MAXQUERYLEN。此时延长保留时间只是拖延失败时间。
- 优先改拉取逻辑:按主键或
ROWID分片,例如每次取 5 万行:SELECT * FROM t_big WHERE id BETWEEN :start_id AND :end_id; - 避免在循环中频繁
COMMIT:实验表明,10 万行分 100 次提交,比 1 次提交慢 3 倍以上,且显著加剧 undo 压力 - 对含 LOB 的大表,考虑加
FLASHBACK_TIME或启用QUERY参数做逻辑过滤,减少扫描量
最常被忽略的一点:即使 UNDO_RETENTION 和表空间都调得合理,只要存在未提交的大事务长期占用 undo 段(比如应用端忘了 commit),UNEXPIRED 块就无法释放,其他查询照样会因无空间可用而触发 ORA-01555。所以排查一定要从 V$TRANSACTION 和 V$SESSION 的 USED_UREC、START_TIME 入手,而不是只盯参数。











