首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 教學

Oracle ORA-01555 Snapshot Too Old 深度解析:兩大成因與四大解決策略

     編輯:Oracle 教學

Oracle ORA-01555 Snapshot Too Old 深度解析:兩大成因與四大解決策略

ORA-01555: snapshot too old 是資料庫常見錯誤,發生於長時間查詢需要一致性讀(Consistent Read)時,對應的 UNDO 已被覆寫。自 9i 引入自動 UNDO 管理、10g/11g 的 Auto Tuning 後發生率大幅降低,但仍無法完全杜絕。本文系統整理兩大核心成因與解決方案。

成因一:長查詢 + UNDO 不足 / 交易過多 / 頻繁 COMMIT(最常見)

  • 查詢執行時間過長,或 UNDO 表空間過小,或同時期大量 DML 產生海量 UNDO,導致查詢啟動時所需的「前映像」已被覆寫,無法構建 CR Block。
  • 頻繁 COMMIT 會加速 UNDO 區段重用,惡化問題。

成因二:延遲區塊清除 + 長查詢 + 大量 COMMIT 導致交易表槽位重用(罕見)

  1. 大量修改並 COMMIT,但修改區塊未完成「提交清除」。
  2. 長查詢啟動(SCN = t1),此時修改交易的槽位仍在 UNDO 交易表中。
  3. 查詢期間發生大量 COMMIT,導致交易表回繞重用槽位,且 UNDO 區段被重用,最低記錄 SCN 超過 t1。
  4. 查詢讀到未清除區塊時,無法判斷修改交易的 COMMIT SCN 是早於/晚於 t1,拋出 ORA-01555。

四大解決策略(針對成因一)

  1. 擴大 UNDO 表空間:ALTER DATABASE DATAFILE ... RESIZE ... 或新增檔案。
  2. 增加 UNDO_RETENTION:預設 900 秒(15 分鐘),建議依最長查詢時間設定,如 ALTER SYSTEM SET UNDO_RETENTION=3600 SCOPE=BOTH;。
  3. 優化出錯 SQL(首選):改善執行計畫、加索引、分頁、減少掃描量,縮短查詢時間。
  4. 避免頻繁 COMMIT:批次處理時適當放大交易邊界。

成因二的專用解法:主動觸發區塊清除

-- 全表掃描觸發清除(不可用 PARALLEL,需 Serial Direct Read)
SELECT /*+ FULL(t) */ COUNT(*) FROM big_table t;
  • COUNT(*) 比 SELECT * 快得多,極低機率觸發 ORA-01555。
  • 必須用 FULL Hint 強制全表掃描,避免 Index Fast Full Scan。
  • 不可加 PARALLEL,並行直讀不會觸發清除。

超大表分段清除腳本

若 COUNT(*) 仍過久,可依 DBA_EXTENTS 將表切分多段,逐段執行 SELECT COUNT(*) FROM table WHERE ROWID BETWEEN ...。完整切分 SQL 見原文。

監控建議

  • 定期查詢 V$UNDOSTAT 觀察 MAXQUERYLEN、UNXPSTEALCNT、EXPSTEALCNT。
  • 啟用 UNDO_MANAGEMENT=AUTO 並設定合理 UNDO_RETENTION。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved