ORACLE技術專題-- 回滾段

xsdan發表於2006-04-28

本專題分為以下幾個部分:
* 回滾段的作用
* 回滾段的型別
* 回滾段的數量、大小及儲存引數
* 回滾段的維護及查詢
* 有關回滾段的常見錯誤及解決方法

[@more@]

1. 回滾段的作用

回滾段用於對資料庫修改時, 儲存原有的資料, 以便稍後可以透過使用ROLLBACK來恢復到修改前的資料; 另外, 回滾段可以為資料庫中的所有程式提供讀一致性. 因此, 回滾段設定的合理與否, 直接影響到資料庫的效能, 在更新密集的OLTP應用中,更是如此.


2. 回滾段的型別
回滾段可分為系統回滾段和非系統回滾段, 其中非系統回滾段又分為PUBLIC回滾段和PRIVATE回滾段.
系統回滾段用於處理涉及系統的CATALOG的事物(比如大多數的DDL), 它位於SYSTEM表空間, 由於只有SYSTEM表空間可以隨時保持可用, 因此, 不要把SYSTEM回滾段放在其他的表空間中.

*** 原則1: 系統回滾段應放在SYSTEM表空間中, 並且應該永遠保持ONLINE狀態.

PUBLIC回滾段對於資料庫的所有例項(INSTANCE)都是可用的, 除非將其顯式設定為OFFLINE.

PRIVATE回滾段是指對於資料庫的某個例項是私有的, 為了使用PRIVATE回滾段, 某個例項應當在其INITsid.ORA的ROLLBACK_SEGMENTS中標明所有要使用的PRIVATE回滾段, 或透過使用ALTER ROLLBACK SEGMENT XXX ONLINE來使用某一個回滾段.

*** 建議1: 在單例項系統中,建議將所有回滾段設為PUBLIC.

*** 建議2: 在多例項系統中(如OPS), 建議將每個例項的PRIVATE回滾段放置到訪問比較快的本地裝置上.


3. 回滾段的數量、大小及儲存引數
精確的回滾段的數量及大小的計算涉及很多方面: 應用的型別(OLTP/OLAP/BATCH), 同時進行的事物的數量, DML語句的型別, 每個事物處理的資料量等等. 精確的計算, 限於篇幅, 不在此提及, 朋友們可參考相關文件(參考文獻4), 在此, 只提供幾個原則及建議.

*** 原則2: OLTP系統應使用小但較多的回滾段, OLAP系統/批處理系統應使用少量的大回滾段

*** 建議3: OLTP/OLAP混合型系統中, 應專門設定一個或幾個大的回滾段, 平時設定為OFFLINE, 使用時透過使用SET TRANSACTION USE ROLLBACK SEGMENT XXX來使用它. 這些回滾段應使用OPTIMAL引數,以便在不使用時,可以SHRINK到一個較小的尺寸。

*** 建議4: 在很難計算準確的數量、大小時,可用"偏大不偏小"的原則。

*** 原則3: 所有的回滾段的INITIAL/NEXT引數應設為相同, 只有建議3中提到的大回滾段例外.

*** 原則4: 不要將回滾段的MAXEXTENTS設為UNLIMITED, 回滾段所在表空間也不要設為AUTOEXTEND

方式, 否則將會使得由於某個不正常的事務導致整個資料庫處於失控狀態.

4. 回滾段的維護及查詢
(1) 建立回滾段
__CREATE ROLLBACK SEGMENT RB01
__TABLESPACE RBS1
__STORAGE (
____INITIAL 100K
____NEXT 100K
____MINEXTENTS 20
____MAXEXTENTS 100
____OPTIMAL 2000K );

2) 更改ONLINE/OFFLINE狀態
__ALTER ROLLBACK SEGMENT RB01 ONLINE;
__ALTER ROLLBACK SEGMENT RB01 OFFLINE;

(3) 更改OPTIMAL引數
__ALTER ROLLBACK SEGMENT RB01
__STORAGE ( MAXEXTENTS 200
____OPTIMAL 2048K );

(4) 縮小回滾段
__ALTER ROLLBACK SEGMENT RB01 SHRINK;
(有OPTIMAL引數時, 縮小到OPTIMAL值; 沒有OPTIMAL引數時, 縮小到MINEXTENTS所對應的尺寸)
__ALTER ROLLBACK SEGMENT RB01 SHRINK TO 2048K;

(5) 修改INITIAL/NEXT引數

*** 建議5: 根據原則3, 修改NEXT時, 總應該同時修改INITIAL.

INITIAL引數無法直接修改, 只能先DROP, 然後再CREATE.

__DROP ROLLBACK SEGMENT RB01;
__CREATE ROLLBACK SEGMENT RB01
__TABLESPACE RBS1
__STORAGE ( INITIAL 100K
____NEXT 100K
____MINEXTENTS 20
____MAXEXTENTS 121
____OPTIMAL 2000K )

(6) 在事務中使用特定的回滾段
__SET TRANSACTION USE ROLLBACK SEGMENT RB_LARGE1;

(7) 常用的有關回滾段的系統資料字典
DBA_ROLLBACK_SEGS (相關表:DBA_SEGMENTS)
V$ROLLNAME
V$ROLLSTAT
V$TRANSACTION (相關表: V$SESSION)

5. 有關回滾段的常見錯誤及解決方法
(1) 回滾段空間不夠
ORA-01562 - failed to extend rollback segment number string
回滾段空間不夠的原因一般有以下幾種情況:
A. 回滾段所在表空間剩餘的空閒空間太小, 無法分配下一個EXTENT.
B. 回滾段擴充套件次數已經達到MAXEXTENTS限制

解決方法:
A. 擴大回滾段所在表空間
B. 設定較大的MAXEXTENTS引數
C. 為回滾段設定OPTIMAL引數
D. 用較大的EXTENT引數重新建立回滾段
C. 將導致ORA-1562錯誤的DML語句改為分段執行:
例如: 原來的語句為
____DELETE FROM HUGETABLE WHERE condition;
可用如下語句代替:
____BEGIN
________LOOP
____________DELETE FROM HUGETABLE
____________WHERE condition
____________AND ROWNUM<10000;
____________EXIT WHEN SQL%NOTFOUND;
____________COMMIT;
________END LOOP;
____END;

(2) ORA-01552 cannot use system rollback segment for non-system tablespace

'string'
原因: 沒有可用的非系統回滾段. 分為以下情形:
A. 除了系統回滾段, 未建立其它回滾段
B. 只建立了PRIVATE回滾段, 但INITsid.ORA的ROLLBACK_SEGMENTS中未列出這些回滾段
C. 建立了PUBLIC回滾段, 但這些回滾段都處於OFFLINE狀態
解決方法: 根據以上原因相應解決即可

(3) ORA_01555 snapshot too old: rollback segment number string with name "string" too small
原因可分為以下情形:
A. 回滾段太少/太小
資料庫中有太多的事務修改資料並提交, 就會發生已提交事務曾使用的空間被重用, 從而造成一個延

續時間長的查詢所請求的資料已經不在回滾段中.
解決方法: 建立更多的回滾段, 為回滾段設定較大的EXTENT以及較大的MINEXTENTS

B. 回滾段被破壞
由於回滾段被破壞, 造成事務無法將修改前的內容(read-consistent snapshot) 放入回滾段, 也會產生ORA-01555錯誤.
解決方法: 將被破壞的回滾段OFFLINE, 刪除重建.

C. FETCH ACROSS COMMIT
當一個程式開啟一個CURSOR, 然後迴圈執行FETCH, UPDATE, COMMIT, 如果更新的表與FETCH的是同一個表, 就很可能發生ORA-01555錯誤.

解決方法:

a. 使用大的回滾段

b. 減少提交頻率(可參見本論壇"如何避免一個PROCEDURE被重複呼叫"一貼中, 無名朋友的回帖)
以上兩種方法只能減少該錯誤發生的可能, 不能完全避免. 如果要完全避免, 須從執行方法著手, 可以用以下兩種方法:

c. 建立一個臨時表, 存放要更新的表的查詢列(如主鍵及相關的條件列), 從臨時表FETCH, 更新原來的表.

d. 捕獲ORA-01555錯誤, 關閉並重新開啟CURSOR, 繼續執行迴圈:
示例(示例程式的思路來源自ORACLE的UTLIP.SQL, 有興趣的朋友可直接閱讀該程式, 位置在RDBMSADMIN下, 程式很短, 容易讀):

____DECLARE
____LAST_PK NUMBER := 0;
____V_THEROWID ROWID;
____CURSOR C1 IS
________SELECT ROWID, PK, …
________FROM SMPLE
________WHERE PK > LAST_PK
________AND othercondition
________ORDER BY PK;
____BEGIN
________OPEN c_SOURCE;
________LOOP
____________BEGIN
________________FETCH C1 INTO v_THEROWID, v_PK;
________________EXIT WHEN C1%NOTFOUND;
____________EXCEPTION WHEN OTHERS THEN
________________IF SQLCODE = -1555 THEN -- snapshot too old, re-execute fetch query
____________________CLOSE C1;
____________________OPEN c_SOURCE;
____________________GOTO NEXTLOOP01555;
________________ELSE
____________________RAISE;
________________END IF;
____________END;
____________LAST_PK := PK;
……… … PROCESS, UPDATE AND COMMIT
____________<>
____________NULL;
________END LOOP;
________CLOSE C1;
____END;

D. 其它原因:
* Delayed logging block cleanout是ORACLE用來提高寫效能的一種機制: 當修改操作(INSERT/UPDATE/DELETE)發生時, ORACLE將原有的內容寫入回滾段, 更新每個資料塊的頭部使其指向相應的回滾段, 當該操作被COMMIT時, ORACLE並不再重新訪問一遍所有的資料塊來確認所有的修改, 而只是更新位於回滾段頭部的事務槽來指明該事務已被COMMIT, 這使得寫操作可以很快結束從而提高了效能接下來的任何訪問該操作所修改的資料的操作會使先前的寫操作真正生效, 從而訪問到新的值. Delayed logging block cleanout 雖然提高了效能, 但卻可能導致ORA-01555. 這種情況下, 在OPEN/FETCH前對該表做全表掃描(保證所有的修改被確認)會有所幫助.

* 不適當的OPTIMAL引數: 太小的OPTIMAL引數會使回滾段很快被SHRINK, 造成後續讀取操作訪問時, 先前的內容已丟失. 仔細設計OPTIMAL引數, 不要讓回滾段過於頻繁的EXTEND/SHRINK有助於問題的解決.

* DB BLOCK BUFFER太小: 如果讀一致性所請求的塊的先前內容在緩衝區中, 那麼就不用去訪問回滾段. 而如果緩衝區太小, 使得先前版本的內容在CACHE中的可能性變小, 從而必須頻繁的訪問回滾段來獲取先前的內容, 這將大大增大ORA-01555發生的可能.

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

相關文章