ORA-01555在ADG备库触发的根本原因是主库UNDO_RETENTION设置无效且未启用RETENTION GUARANTEE,导致备库查询所需的历史UNDO被覆盖;必须同时调大UNDO_RETENTION、启用RETENTION GUARANTEE并确保UNDO表空间自动扩展,缺一不可。
ora-01555在adg备库上不是备库配置问题,而是主库undo_retention设置无效或undo表空间无法真正保留旧镜像导致的。
为什么ADG备库只读查询会触发ORA-01555
ADG备库本身不生成UNDO,它回放主库归档/实时日志时,依赖主库产生的UNDO记录来构造一致性读(CR)块。当备库上一个查询需要访问某个SCN之前的数据版本,而该版本对应的UNDO块已在主库被覆盖,就会报ORA-01555: snapshot too old——错误源头永远在主库,不在备库。
常见误判点:
- 以为备库开了归档、日志已应用就“万事大吉”,但归档日志里不存UNDO,只存重做;
- 在备库查
v$undostat发现maxquerylen很高,就去调备库参数,实际毫无作用; - 看到主库
undo_retention=3600,就认为“1小时内肯定安全”,忽略了RETENTION GUARANTEE未启用时,这只是一个软建议。
必须同时生效的两个主库操作
只改UNDO_RETENTION或只加RETENTION GUARANTEE都不够,二者缺一不可,且需确认底层空间支撑得住。
-
ALTER SYSTEM SET UNDO_RETENTION = 3600 SCOPE=BOTH;—— 设为查询最长耗时的1.5倍以上(查v$undostat.maxquerylen) -
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;—— 替换undotbs1为实际UNDO表空间名 - 检查UNDO表空间是否启用自动扩展:
SELECT file_name, autoextensible, maxbytes FROM dba_data_files WHERE tablespace_name = (SELECT value FROM v$parameter WHERE name = 'undo_tablespace');若autoextensible为NO,必须先执行ALTER DATABASE DATAFILE '/path/to/undotbs01.dbf' AUTOEXTEND ON NEXT 100M MAXSIZE 20G;
没开AUTOEXTEND却启RETENTION GUARANTEE,会导致主库很快报ORA-30036(无法扩展UNDO),比ORA-01555更严重。
备库侧唯一可控的缓解手段
你不能改主库参数?那只能从查询端收口。长查询越久,所需历史SCN越老,撞上被覆盖UNDO的概率指数级上升。
- 禁用无WHERE条件的全表扫描,尤其是
SELECT * FROM big_table类语句; - 避免未绑定变量的SQL(如
WHERE id = 123硬编码),防止硬解析+执行计划抖动拉长一致性读链; - 对已知慢查询,可临时加提示:
/*+ OPT_PARAM('_serial_direct_read' 'never') */,强制走buffer cache读CR块(但只是权宜之计); - 更可靠的做法:用
DBMS_FLASHBACK.ENABLE_AT_SYSTEM_CHANGE_NUMBER显式指定一个较新的SCN,把一致性读窗口缩窄。
最容易被忽略的兼容性细节
Oracle 12c起引入IN-Memory(IM)列存储,若备库开启了INMEMORY并涉及IM表查询,ORA-01555可能叠加IM压缩单元刷新机制,导致CR块构造失败。此时即使主库UNDO一切正常,也建议在备库关闭IM相关对象或显式加NO_INMEMORY提示。
另外,statistics_level = BASIC会禁用AWR,使v$undostat.tuned_undoretention失效,SMON无法动态调整,等于让UNDO_RETENTION彻底退化为摆设——这点在19c中仍常被遗漏。











