ORA-1555錯誤解決大全

BTxigua發表於2007-10-18
ORA-1555錯誤解決大全

ORA-1555錯誤簡單的說就是針對一個資料塊產生一致讀時發生了錯誤。一致讀就是指ORACLE利用回滾段來臨時重構一個和事務或查詢開始時的 塊狀態相同的快照塊的過程。如果一個塊改變了多次,可能就會有多個快照塊的。
一個事務或查詢開始執行時,ORACLE會產生一個SCN來記錄這個開始時刻點,這個SCN也就叫做SNAPSHOT SCN。ORACLE僅僅看基於SNAPSHOT SCN的快照記錄。如果塊中有活動的事務或BLOCK SCN> SNAPSHOT SCN時,就產生了一致讀。如果是沒有活動的事務但沒有產生COMMIT SCN的塊 ,先產生DELAY BLOCK CLEANOUT,再比較COMMIT SCN與SNAPSHOT SCN的大小,如果COMMIT SCN小於SNAPSHOT SCN則直接使用該塊,否則要產生一致讀。

產生ORA-1555的可能情況:
1 一個長時間執行的查詢,並同時針對查詢需要的塊有DML處理(主要是update和delete)
2 當查詢和插入併發時
3 延遲塊清除
4 交叉fetch和commit
5 回滾段發生錯誤

情況1 一個長時間執行的查詢,並同時針對查詢需要的塊有DML處理(主要是update和delete)
當一個查詢開始之後,正好某一個update更改了其中的一個記錄,當查詢掃描到該記錄時,就需要一致讀,回滾空間中去查詢原值。如果這個查詢的時間非常長,而那條記錄修改之後,很快就被提交了,導致回滾空間中的記錄可以被清除,並且這個資料庫事務本身也比較多,回滾空間的覆蓋比較塊,在查詢結束之前,回滾段中的記錄空間就被新的記錄覆蓋佔用了,導致查詢找不到原值,從而產生ORA-1555錯誤。
Solution:
1、業務控制,禁止對同一個表的長時間查詢和更新處理同時進行,要分開執行
2、增大回滾段的大小
3、增加回滾段的個數
4、不使用OPTIMAL選項,已經被使用的空間就不會很快收縮回來,可以使commit之後的記錄保持儘可能長的時間
5、推遲對DML語句的COMMIT
6、優化查詢語句,比如並行查詢,目的是減小查詢的時間
7、為要查詢的表建立只讀SNAPSHOT,這樣對錶記錄的修改就不會影響到查詢,但該表不能是太大的表

情況2 當查詢和插入併發時
一般情況下,當我們查詢一個表,同時對這個表作插入,這時是不需要一致讀的。當然這種情況下也不可能產生ORA-1555錯誤。
當作全表掃描的時候,oracle會掃描所有位於HWM之下的空間,而對於HWM之上的空間將忽略。也正因為如此,當我們插入的資料位於HWM之下的時候,如果同時還有例如全表掃描這部分空閒的空間,就會產生一致讀,就有可能會導致ORA-1555錯誤。 特別是在VLDB和OPS系統中,因為在這些系統中,很多時候都會對錶作pre-allocate,當作了預分配之後,如果作一次大批量的delete,將會有非常多的可用空間位於HWM之下。
Solutions:
1、情況1的所有解決方法這裡同樣適用
2、不要預分配區(pre-allocate extent)
3、使用tuncate來刪除表記錄,使HWM收縮。
4、使用直接路徑選項匯入資料,使插入的資料在HWM之上。

情況3 延遲塊清除
關於延遲塊清除的概念,可以參考後面的附錄。
Solution:
1、使用oracle並行伺服器OPS,將DML操作分割到不同的例項上執行
2、在批處理中使用SET TRANSACTION USE ROLLBACK SEGMENT為事務單獨指定一個回滾段。
3、可以在DML之後,立即執行一個全表掃描和analyze indexes來強制立即進行塊清除。

情況4 交叉fetch和commit
這種比較典型的情況是在一個過程中使用瞭如下的結構:
cursor c1 is select * from bigemp;
begin
for c1rec in c1 loop
  update mydual set a=a;
  commit;
end loop;
end ;

Solution:
1、檢查過程,避免這種交叉提取和提交的情況出現。
2、延遲commit
3、在查詢語句中,增加“ order by 1 ”的語句,這樣會在臨時段中保留ORDER BY的結果,可以避免一些一致讀。

情況5 回滾段發生錯誤的解決方法:
由這種原因導致的ORA-01555錯誤是極少數的。一般情況下,也只有在那些不支援大檔案的作業系統會發生這種情況。
Solution:
1、檢查init.ora中的引數檔案,show parameter CORRUPT,可以將結果提交給ORACLE SUPPORT SERVICES。如果這樣的引數存在,建議重 建資料庫。
2、檢查作業系統是否支援ORACLE。檢查作業系統的錯誤日誌和ORACLE的錯誤日誌。
3、向Oracle Support Services尋求幫助。

補充情況6:
在oracle 9i之後,使用auto的undo,就很少出現ORA-1555錯誤了,但是也不能完全排除這個錯誤,比如以下錯誤:
ORA-01555 caused by SQL statement below (Query Duration=11952 sec, SCN: 0x0842.1a1d737c)
這種情況下,主要是查詢的時間超長,超過了undo_retention設定的時間10800秒,從而產生前面的情況1和情況2的錯誤。
Solution:
主要的解決方法,還是優化查詢,包括語句的優化和索引的優化。

附錄1:關於事務和資料塊的一個說明
一個回滾段能夠被多個事務使用;一個extent也可以被多個事務共享;但是一個block只能被一個active的事務使用;
8i中:一個事物只能使用一個回滾段;
9i中:一個事務可以使用多個回滾段;
commit以後rollback segment裡還會儲存undo_retention 秒.這樣以使在執行DML語句以前的開始的大查詢在commit以後還是使用修改以前的資料,以保持查詢的一致性,否則會產生snapshot too old這個錯誤


附錄2:什麼是延遲塊清除(delayed block cleanout)
塊清除就是刪除所修改資料塊上與"鎖定"有關的資訊,即事務資訊。Oracle在事務相關的提交列表中,記錄下已修改的塊列表,每個列表記錄20個塊,根據需要可能分配有多個這種列表.這種塊列表有一個上限,就是緩衝區快取大小的10%.如果一次修改的塊,沒有超過了緩衝區快取大小的10%,並且這些塊在記憶體中,則commit時,會清除塊上的事務資訊。如果,一次修改的塊超過了這個上限值,oracle在commit的時候就不會清除塊頭的事務資訊,直到下次訪問這些塊時,再清除塊中的事務資訊,這就是延遲塊清除.
當事務提交(假設commit scn為T1),如果該事務是一個大事務,涉及了很多個資料塊,超過了data buffer的10%,則提交的時候, oracle並不會再次逐一將commit scn(T1)寫到所有相關的data block的ITL上。或者另一種情況是提交的時候,因為某種原因,修改的內容已經被DBWR給寫到資料塊中,這時,oracle也不會將commit scn(T1)寫到該資料塊的ITL上。
上面這兩種情況的結果是,當之後的事務,比如select(假設scn 為T2)來訪問這個資料塊的時候,發現在ITL上找不到commit scn,因此無法判斷是否需要回退,所以select轉而去回滾段中查詢相關資訊確認是否需要回退。如果在回滾段中找到真實的commit scn(T1),則該事務會將該commit scn(T1)寫到資料塊的ITL中。之後的查詢將可以直接通過ITL確定資料塊的狀態資訊。
如果在回滾段中沒有找到真實的commit scn(T1)(由於事務提交頻繁,將回滾段覆蓋了),則查詢該回滾段中的最小scn(T3),若T3T2,則commit是發生在select之前,還是之後,就會報ORA-01555錯誤。

下面是關於延遲清除的示例
1)初始狀態
  這個是最開始的情形,在資料塊的頭部,有一個tx區域,用來保留指向回滾段中的相關活動事務,在回滾段頭中則包含有一張儲存了所有最近使用了該回滾段的事務資訊表。
  在下面的例子中,回滾段頭的表中包含了兩個活動的事務資訊(事務槽01和事務槽02),後面的事務槽則都是已經commit的,可以再次使用的。
  Data Block 500       Rollback Segment Header 5
  +----+--------------+   +----------------------+---------+
  | tx | None     |   | transaction entry 01 |ACTIVE  |
  +----+--------------+   | transaction entry 02 |ACTIVE  |
  | row 1       |   | transaction entry 03 |COMMITTED|
  | row 2       |   | transaction entry 04 |COMMITTED|
  | ... ..      |   |   ...   ...  .. | ...  |
  | row n       |   | transaction entry nn |COMMITTED|
  +-------------------+    +--------------------------------+
  
2)更新了row 2
  下面更新資料塊中的row 2。此時,資料塊頭部tx區域已更新指向回滾段中的事務槽3(5.3)的位置,事務槽03已經被標記為active。
  Data Block 500       Rollback Segment Header 5
  +----+--------------+   +----------------------+---------+
  | tx |5.3uncommitted|-+  | transaction entry 01 |ACTIVE  |
  +----+--------------+ |  | transaction entry 02 |ACTIVE  |
  | row 1       | +--&gt | transaction entry 03 |ACTIVE  |
  | row 2 *changed*  |   | transaction entry 04 |COMMITTED|
  | ... ..      |   |   ...   ...  .. | ...  |
  | row n       |   | transaction entry nn |COMMITTED|
  +------------------+   +--------------------------------+
  
3)commit
  之後,使用者提交了該更新操作。提交操作更新的回滾段頭部的事務列表資訊,將事務槽03從active狀態更新為commited狀態。但對於資料塊卻未作任何操作。
  Data Block 500          Rollback Segment Header 5
  +----+--------------+    +----------------------+---------+
  | tx |5.3uncommitted|--+  | transaction entry 01 |ACTIVE  |
  +----+--------------+ |  | transaction entry 02 |ACTIVE  |
  | row 1       | +---&gt | transaction entry 03 |COMMITTED|
  | row 2 *changed*  |    | transaction entry 04 |COMMITTED|
  | ... ..      |    |   ...   ...  .. | ...  |
  | row n       |    | transaction entry nn |COMMITTED|
  +------------------+    +--------------------------------+
  
4)commit之後的其他事務訪問
  過了一段時間之後,另外一個使用者(或者同一個使用者)再次訪問該資料塊,我們其實可以看到,在資料塊的頭部資訊中,並沒有關於row 2已經提交的資訊。
oracle利用資料塊的頭部資訊找到與row 2更新事務相關的回滾段的段頭的列表資訊。在這裡發現,該事務已經提交,則更新資料塊的資訊 ,表明row 2已經commited。
  
  Data Block 500          Rollback Segment Header 5
  +----+--------------+   +----------------------+---------+
  | tx | None     |   | transaction entry 01 |ACTIVE  |
  +----+--------------+   | transaction entry 02 |ACTIVE  |
  | row 1       |   | transaction entry 03 |COMMITTED|
  | row 2       |   | transaction entry 04 |COMMITTED|
  | ... ..      |   |   ...   ...  .. | ...  |
  | row n       |   | transaction entry nn |COMMITTED|
  +------------------+    +--------------------------------+


附錄3:什麼是ITL事務槽?--Interested Transaction List(ITL)
ITL內容包括:
xid---Transaction ID
Uba---Undo Block Address
Lck---Lock Status
Oracle在讀一個block時,如果ITL事務槽存在活動事務,那麼Oracle會根據相應的xid找到相應的回滾段以判斷事務狀態.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10867315/viewspace-194846/,如需轉載,請註明出處,否則將追究法律責任。

相關文章