ORA-01555 根因是查询所需旧版本UNDO被覆盖,需同步排查“谁在用UNDO”和“UNDO能否留住”;关键看maxquerylen与undo_retention匹配度、UNDO表空间真实使用率及AUTOEXTEND状态、RETENTION GUARANTEE是否启用,并关联v$session/v$rollstat定位长事务与高频修改对象。

ORA-01555 不是 SQL 写错了,也不是数据丢了,而是查询需要的旧版本数据(UNDO 中的一致性读镜像)被覆盖了——排查必须从“谁在用 UNDO”和“UNDO 能不能留得住”两个维度同步切入。
查当前最长查询耗时与 UNDO_RETENTION 是否匹配
ORA-01555 的直接诱因永远是:查询运行时间 > 可用 UNDO 保留窗口。别先改参数,先确认差距有多大。
- 执行
SELECT MAX(maxquerylen) FROM v$undostat,拿到最近 7 天内最长查询秒数(比如返回2840) - 对比当前
UNDO_RETENTION值:SHOW PARAMETER undo_retention(若为900,说明窗口只有 15 分钟,远不够) - 安全值不是拍脑袋定的:
UNDO_RETENTION至少设为maxquerylen × 1.5(如 2840 → 建议设为4200) - 注意:
v$undostat.maxquerylen是统计值,可能滞后;如果应用里明确有跑 30 分钟以上的报表,就按实际时间来
看 UNDO 表空间真实使用率和 AUTOEXTEND 状态
只看 dba_free_space 会误判——UNDO 表空间的“已用空间”包含未过期(UNEXPIRED)和过期(EXPIRED)两部分,真正危险的是前者长期占满。
- 查真实压力:
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') - 查自动扩展是否启用:
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 = 'NO',立刻执行:ALTER DATABASE DATAFILE '/path/to/undotbs01.dbf' AUTOEXTEND ON NEXT 100M MAXSIZE 20G(路径以查询结果为准) -
expstealcount > 0或UNEXPIRED占比持续 >95%,说明 UNDO 块正在被强制覆盖,此时调高UNDO_RETENTION毫无意义
确认 RETENTION GUARANTEE 是否启用且空间可支撑
没开 RETENTION GUARANTEE,UNDO_RETENTION 就只是个建议;开了却没配 AUTOEXTEND,主库会很快报 ORA-30036(无法扩展 UNDO),比 ORA-01555 更致命。
- 检查是否启用:
SELECT tablespace_name, retention FROM dba_tablespaces WHERE contents = 'UNDO',若retention为NOGUARANTEE,需立即修正 - 启用命令:
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE(替换undotbs1为实际 UNDO 表空间名) - 但必须前置确认:
AUTOEXTEND已开 +MAXSIZE足够(建议至少预留 1.5 倍峰值需求) - ADG 备库报 ORA-01555?根子一定在主库——备库不生成 UNDO,它依赖主库回放日志时产生的 UNDO 镜像。只调备库参数无效
定位具体出问题的 SQL 和源头事务
报错日志里带的 rollback segment number 已废弃(10g+ 后用自动段管理),得靠关联视图抓实时上下文。
- 查当前长时间运行的查询:
SELECT sid, serial#, sql_id, prev_sql_id, status, last_call_et FROM v$session WHERE status = 'ACTIVE' AND last_call_et > 600(运行超 10 分钟的活跃会话) - 查最近被覆盖的 UNDO 块来源:
SELECT usn, state, undoblocks, txncount FROM v$rollstat ORDER BY undoblocks DESC,结合v$transaction找对应事务 - 查哪些对象被高频修改:
SELECT object_name, subobject_name, statistic_name, value FROM v$segment_statistics WHERE statistic_name IN ('logical reads', 'db block changes') AND value > 1000000 ORDER BY value DESC - 特别注意:
expdp、物化视图COMPLETE刷新、存储过程里OPEN后长期不FETCH的游标,这三类场景最易触发,解法各不相同——不能一概调参
最容易被忽略的一点:UNDO 压力从来不是孤立存在的。一个看似简单的 SELECT * FROM big_table,如果搭配硬编码 WHERE id = 123 导致未绑定变量,就会引发大量硬解析 + 执行计划抖动,间接拉长一致性读链,让原本 5 分钟的查询变成 12 分钟,直接撞上 UNDO 边界。排查时一定要把 SQL 写法、绑定习惯、执行计划稳定性一起看。











