ORA-01555: Snapshot too old(Oracle)
Oracle 的 'ORA-01555: snapshot too old' 错误表示查询进行一致性读所需的旧数据(undo)已被覆盖。此决策树缩小错误来源的范围(长查询 + UNDO 不足、undo 周转过快或 LOB),并引导你找到正确的修复方法。
错误发生在哪里?
先确定错误发生的上下文。经典的 ORA-01555 是在长时间运行的 SELECT/报表期间出现,还是在访问 LOB(CLOB/BLOB)列时出现?与 LOB 相关的 ORA-01555 是另一种机制(PCTVERSION/RETENTION),需单独解决。
SELECT sql_id, elapsed_time/1e6 AS sec, sql_text
FROM v$sql ORDER BY elapsed_time DESC FETCH FIRST 10 ROWS ONLY;- 在长时间运行的查询/报表期间
- 在访问 LOB 列时
UNDO 是否足够,保留时间是否合适?
长查询从 UNDO 中读取自其开始以来被修改过的块的旧映像。若 UNDO 表空间太小或 undo_retention 短于查询时长,旧 undo 就会被覆盖。测量 UNDO 使用情况和保留时间。
SHOW PARAMETER undo_retention;
SELECT tablespace_name, SUM(bytes)/1024/1024 AS mb, status
FROM dba_undo_extents GROUP BY tablespace_name, status;
SELECT MAX(maxquerylen) AS longest_query_sec, MAX(tuned_undoretention) AS tuned_retention
FROM v$undostat;- UNDO 太小/保留时间短于查询时长
- UNDO 足够,但提交非常频繁
- 查询运行时间过长
根本原因:UNDO/保留时间不足
长查询所需的旧 undo 因保留期到期或表空间写满而被覆盖。扩大 UNDO,并将保留时间设置为能覆盖查询时长。
根本原因:undo 周转过快(频繁提交)
提交非常频繁的大量 DML 会快速循环使用 undo 块,抹掉长查询所需的旧映像。'commit cleanout' 效应会使情况更糟。
根本原因:查询时长过长
查询运行时间太长,即使合理的 undo_retention 也不够。永久的解决办法是加快查询或分流其负载。
根本原因:LOB 保留 / PCTVERSION
读取 LOB 时出现 ORA-01555,说明保存旧 LOB 版本的空间(RETENTION 或 PCTVERSION)不足。LOB 有单独的版本机制。