原創文章,轉載請注明: 轉載自dbtan 談DB
本文鏈接地址: http://www.dbtan.com/2010/01/ora-01555-reason-and-solution.html
ORA-01555 原因與解決:
前面提到了ORA-01555錯誤,那么現在來看一下ORA-01555錯誤是怎樣產生的。由於回滾段是循環使用的,當事務提交以后,該事務占用的回滾段事務會被標記為非活動,回滾段空間可以被覆蓋重用。那么一個問題就出現了,如果一個查詢需要使用被覆蓋的回滾段構造前鏡像實現一致性讀,那么此時就會出現Oracle著名的ORA-01555錯誤。
ORA-01555錯誤的另外一個原因是因為延遲塊清除(Delayed Block Cleanout)。當一個查詢觸發延遲塊清除時,Oracle需要去查詢回滾段獲得該事務的提交SCN,如果事務的前鏡像信息已經被覆蓋,並且查詢SCN也小於回滾段中記錄的最小提交SCN,那么Oracle將無從判斷查詢SCN和事務提交SCN的大小,此時出現延遲塊清除導致的ORA-01555錯誤。
另外一種導致ORA-01555錯誤的情況出現在使用sqlldr直接方式加載(direct=true)數據時。當通過sqlldr direct=true 方式加載數據時,由於不產生重做和回滾信息,Oracle直接指定Cached Commit SCN 給加載數據,在訪問這些數據時,有時會產生ORA-01555錯誤。
看下圖的描述:假定在時間T用戶A發出一條更新語句,更新SCOTT用戶的SAL;用戶B在Ty時間發出查詢語句,查詢SCOTT用戶的SAL;用戶A的更新在Tx時間提交,提交可能為快速提交塊清除,也可能是延遲塊清除;用戶B的查詢在Tz時間輸出。

來看一下數據庫在不同情況下的內部處理:
·如果 Ty < T < Tz < Tx ,那么查詢需要構造一致性讀,由於事務尚未提交,可以通過回滾段構造前鏡像,完成一致性讀取。
·如果 Ty < T < Tx < Tz ,由於Ty查詢時間小於T事務更新時間,那么數據庫需要構造一致性讀取,而Tz查詢完成時間大於Tx提交時間,那么前鏡像就有可能被覆蓋,不可獲取。如果Tx的提交方式為Fast Block Cleanout,那么回滾段信息不可用時就會出現一致性讀ORA-01555錯誤。
如果Tx的提交方式為Delayed Block Cleanout,那么回滾段信息不可用時Oracle將無法判斷Ty和Tx的時間先后關系。如果 Ty > Tx ,那么Oracle可以正常進行塊清除,並將塊清除后的數據返回給用戶B;如果 Ty < T ,那么Oracle需要繼續構造一致性讀返回給用戶B;Oracle無法判斷這兩種情況,就會出現延遲塊清除ORA-01555錯誤。
ORA-01555的直觀解釋是“snapshot too old”,也就是快照太舊,其根本含義就是查詢需要的前鏡像過於“久遠”,已經無法找到了。可以想象,如果一個歷時數個小時或十幾個小時的查詢,如果最后遭遇ORA-01555錯誤而失敗,會是多么令人沮喪的一件事。一直以來,ORA-01555都是ORACLE最為頭痛的問題之一。
在Oracle 9i的文檔中這樣描述ORA-01555錯誤:
01555, 00000, "snapshot too old: rollback segment number %s with name \"%s\" too small"
// *Cause: rollback records needed by a reader for consistent read are
// overwritten by other writers
// *Action: If in Automatic Undo Management mode, increase undo_retention
// setting. Otherwise, use larger rollback segments
可以看到,在Oracle 9i自動管理UNDO表空間模式下,UNDO_RETENTION參數的引入正是為了減少ORA-01555錯誤的出現。這個參數設置當事務提交之后(回滾段變得非活躍),回滾段中的前鏡像數據在被覆蓋前保留的時間,該參數以秒為單位,9iR1初始值為900秒,在Oracle 9iR2增加為10800秒。
顯然該參數設置的越高就越能減少ORA-01555錯誤的出現,但是保留時間和存儲空間是緊密相關的,如果UNDO表空間的存儲空間有限,那么Oracle就會選擇回收已提交事務占用的空間,置UNDO_RETENTION參數於不顧。
在Oracle 9i的AUM模式下,UNDO_RETENTION實際上是一個非擔保(NO Guaranteed)限制。也就是說,如果有其他事務需要回滾空間,而空間出現不足時,這些信息仍然會被覆蓋;從Oracle 10g開始,Oracle對於UNDO增加了Guarantee控制,也就是說,可以指定UNDO表空間必須滿足UNDO_RETENTION的限制。當UNDO表空間設置為Guarantee,那么提交事務的回滾空間必須被保留足夠的時間,如果UNDO表空間的空間不足,那么新的事務會因空間不足而失敗,而不是選擇之前的覆蓋。
從各個不同版本回滾段的管理變遷,我們可以看出Oracle一直在進步。
Oracle提供了一個內部事件(10203事件)可以用來跟蹤數據庫的塊清除操作,10203事件可以通過以下命令設置,設置后需要重新啟動數據庫該參數方能生效:
alter system set event="10203 trace name context forever" scope=spfile;
需要注意的是,可能存在另外一種情況,就是當執行延遲塊清除時,回滾段或原回滾表空間已經被刪除,此時Oracle仍然可以通過字典表UNDO$來獲得SCN信息,執行塊清除。
關於Oracle的提交處理及塊清除機制是一個極其復雜的過程,本文對這部分內容進行了適當簡化說明,旨在使大家能夠對Oracle的回滾機制、塊清除機制有所了解。
- The End -
