ora-01555 根本原因是 undo 表空间物理空间不足且未启用 retention guarantee,而非 undo_retention 参数过小;须先检查 autoextensible 状态与真实使用率,再结合 v$undostat.maxquerylen 设置合理值并启用保证机制。

ORA-01555 不是参数没设够,而是 UNDO_RETENTION 没被真正遵守——根本卡点在空间和保证机制上。
查真实 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 - 查真实使用率(别只看
dba_free_space):SELECT tablespace_name, ROUND((bytes - free_bytes)/1024/1024) AS used_mb FROM dba_data_files d, (SELECT tablespace_name, NVL(SUM(bytes), 0) free_bytes FROM dba_free_space GROUP BY tablespace_name) f WHERE d.tablespace_name = f.tablespace_name AND d.tablespace_name = (SELECT value FROM v$parameter WHERE name = 'undo_tablespace'); - 若
used_mb接近max_mb,且AUTOEXTENSIBLE = NO,所有参数调整都无效——必须先执行ALTER DATABASE DATAFILE '/path/to/undotbs01.dbf' AUTOEXTEND ON NEXT 100M MAXSIZE 10G;
主库必须同时生效的两个关键操作
ADG 备库报 ORA-01555,根子永远在主库。只改一个参数等于白改。
-
ALTER SYSTEM SET UNDO_RETENTION = 3600 SCOPE=BOTH;—— 值不能拍脑袋定,应为v$undostat.maxquerylen的 1.5 倍以上(查SELECT MAX(maxquerylen) FROM v$undostat WHERE begin_time > SYSDATE - 1;) -
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;—— 替换undotbs1为实际 UNDO 表空间名;没这句,UNDO_RETENTION只是软建议,Oracle 空间一紧就覆盖未过期 undo - 二者缺一不可,且必须确保 UNDO 表空间有足够物理空间支撑;开了
RETENTION GUARANTEE却没开AUTOEXTEND,主库会很快报ORA-30036,比 ORA-01555 更致命
为什么盲目调高 UNDO_RETENTION 反而让问题更糟
UNDO_RETENTION 是“建议值”,不是承诺。当 UNDO 表空间吃紧,Oracle 会优先回收 UNEXPIRED 状态的块(已提交但未到保留时间),哪怕你设了 7200 秒。
- 盲目把
UNDO_RETENTION从 900 调到 3600,若表空间无自动扩展,会导致活跃 undo 堆积更快,NOSPACEERRCNT在v$undostat中飙升 - 查
v$undostat中unexpired占比是否长期超 95%:若持续高位,说明 UNDO 块正在被强制覆盖,此时调参毫无意义 - 用
SELECT begin_time, end_time, undoblks, txncount, ssolderrcnt, nospaceerrcnt FROM v$undostat WHERE begin_time > SYSDATE - 1/24 ORDER BY begin_time DESC;定位分钟级压力突增点,比 AWR 更准
备库侧唯一可控的缓解手段:收窄查询本身
你不能改主库参数?那就只能从 SQL 端卡住风险点。长查询时间越久,撞上被覆盖 UNDO 的概率是指数级上升的。
- 禁用无
WHERE条件的全表扫描,尤其是SELECT * FROM big_table类语句 - 避免硬编码值导致未绑定变量,比如
WHERE id = 123—— 硬解析 + 执行计划抖动会拉长一致性读链 - 对已知慢查询,可临时加提示:
/*+ OPT_PARAM('_serial_direct_read' 'never') */,强制走 buffer cache 读 CR 块(绕过 direct path read 跳过 CR 构造) - 真正可靠的做法:在备库上用
DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER显式指定一个较新的 SCN,缩小一致性读窗口
最常被忽略的一点:RETENTION GUARANTEE 和 AUTOEXTEND 必须共存,否则不是治错,是埋雷。调参前不看 v$undostat.maxquerylen 和真实空间水位,等于闭眼开车。











