1. 回滾段的作用
回滾段用于對數(shù)據(jù)庫修改時, 保存原有的數(shù)據(jù), 以便稍后可以通過使用ROLLBACK來恢復(fù)到修改前的數(shù)據(jù); 另外, 回滾段可以為數(shù)據(jù)庫中的所有進程提供讀一致性. 因此, 回滾段設(shè)置的合理與否, 直接影響到數(shù)據(jù)庫的性能, 在更新密集的OLTP應(yīng)用中,更是如此.
2. 回滾段的類型
回滾段可分為系統(tǒng)回滾段和非系統(tǒng)回滾段, 其中非系統(tǒng)回滾段又分為PUBLIC回滾段和PRIVATE回滾段.
系統(tǒng)回滾段用于處理涉及系統(tǒng)的CATALOG的事物(比如大多數(shù)的DDL), 它位于SYSTEM表空間, 由于只有SYSTEM表空間可以隨時保持可用, 因此, 不要把SYSTEM回滾段放在其他的表空間中.
*** 原則1: 系統(tǒng)回滾段應(yīng)放在SYSTEM表空間中, 并且應(yīng)該永遠保持ONLINE狀態(tài).
PUBLIC回滾段對于數(shù)據(jù)庫的所有實例(INSTANCE)都是可用的, 除非將其顯式設(shè)置為OFFLINE.
PRIVATE回滾段是指對于數(shù)據(jù)庫的某個實例是私有的, 為了使用PRIVATE回滾段,某個實例應(yīng)當(dāng)在其INITsid.ORA的ROLLBACK_SEGMENTS中標(biāo)明所有要使用的PRIVATE回滾段, 或通過使用ALTERROLLBACK SEGMENT XXX ONLINE來使用某一個回滾段.
*** 建議1: 在單實例系統(tǒng)中,建議將所有回滾段設(shè)為PUBLIC.
*** 建議2: 在多實例系統(tǒng)中(如OPS), 建議將每個實例的PRIVATE回滾段放置到訪問比較快的本地設(shè)備上.
3. 回滾段的數(shù)量、大小及存儲參數(shù)
精確的回滾段的數(shù)量及大小的計算涉及很多方面: 應(yīng)用的類型(OLTP/OLAP/BATCH), 同時進行的事物的數(shù)量, DML語句的類型,每個事物處理的數(shù)據(jù)量等等. 精確的計算, 限于篇幅, 不在此提及, 朋友們可參考相關(guān)文檔(參考文獻4), 在此, 只提供幾個原則及建議.
*** 原則2: OLTP系統(tǒng)應(yīng)使用小但較多的回滾段, OLAP系統(tǒng)/批處理系統(tǒng)應(yīng)使用少量的大回滾段
*** 建議3: OLTP/OLAP混合型系統(tǒng)中, 應(yīng)專門設(shè)置一個或幾個大的回滾段, 平時設(shè)置為OFFLINE, 使用時通過使用SETTRANSACTION USE ROLLBACK SEGMENT XXX來使用它.這些回滾段應(yīng)使用OPTIMAL參數(shù),以便在不使用時,可以SHRINK到一個較小的尺寸。
*** 建議4: 在很難計算準(zhǔn)確的數(shù)量、大小時,可用”偏大不偏小”的原則。
*** 原則3: 所有的回滾段的INITIAL/NEXT參數(shù)應(yīng)設(shè)為相同, 只有建議3中提到的大回滾段例外.
*** 原則4: 不要將回滾段的MAXEXTENTS設(shè)為UNLIMITED, 回滾段所在表空間也不要設(shè)為AUTOEXTEND方式, 否則將會使得由于某個不正常的事務(wù)導(dǎo)致整個數(shù)據(jù)庫處于失控狀態(tài).
4. 回滾段的維護及查詢
(1) 創(chuàng)建回滾段
__CREATE ROLLBACK SEGMENT RB01__TABLESPACE RBS1__STORAGE (____INITIAL 100K____NEXT 100K____MINEXTENTS 20____MAXEXTENTS 100____OPTIMAL 2000K );
2) 更改ONLINE/OFFLINE狀態(tài)
__ALTER ROLLBACK SEGMENT RB01 ONLINE;__ALTER ROLLBACK SEGMENT RB01 OFFLINE;
(3) 更改OPTIMAL參數(shù)
__ALTER ROLLBACK SEGMENT RB01__STORAGE ( MAXEXTENTS 200____OPTIMAL 2048K );
(4) 縮小回滾段
__ALTER ROLLBACK SEGMENT RB01 SHRINK;(有OPTIMAL參數(shù)時, 縮小到OPTIMAL值; 沒有OPTIMAL參數(shù)時, 縮小到MINEXTENTS所對應(yīng)的尺寸)__ALTER ROLLBACK SEGMENT RB01 SHRINK TO 2048K;
(5) 修改INITIAL/NEXT參數(shù)
*** 建議5: 根據(jù)原則3, 修改NEXT時, 總應(yīng)該同時修改INITIAL.
INITIAL參數(shù)無法直接修改, 只能先DROP, 然后再CREATE.
__DROP ROLLBACK SEGMENT RB01;__CREATE ROLLBACK SEGMENT RB01__TABLESPACE RBS1__STORAGE ( INITIAL 100K____NEXT 100K____MINEXTENTS 20____MAXEXTENTS 121____OPTIMAL 2000K )
(6) 在事務(wù)中使用特定的回滾段
__SET TRANSACTION USE ROLLBACK SEGMENT RB_LARGE1;
(7) 常用的有關(guān)回滾段的系統(tǒng)數(shù)據(jù)字典
DBA_ROLLBACK_SEGS (相關(guān)表:DBA_SEGMENTS)V$ROLLNAMEV$ROLLSTATV$TRANSACTION (相關(guān)表: V$SESSION)
5. 有關(guān)回滾段的常見錯誤及解決方法
(1) 回滾段空間不夠
ORA-01562 - failed to extend rollback segment number string
回滾段空間不夠的原因一般有以下幾種情況:
A. 回滾段所在表空間剩余的空閑空間太小, 無法分配下一個EXTENT.
B. 回滾段擴展次數(shù)已經(jīng)達到MAXEXTENTS限制
解決方法:
A. 擴大回滾段所在表空間
B. 設(shè)置較大的MAXEXTENTS參數(shù)
C. 為回滾段設(shè)置OPTIMAL參數(shù)
D. 用較大的EXTENT參數(shù)重新創(chuàng)建回滾段
C. 將導(dǎo)致ORA-1562錯誤的DML語句改為分段執(zhí)行:
例如: 原來的語句為
____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’
原因: 沒有可用的非系統(tǒng)回滾段. 分為以下情形:
A. 除了系統(tǒng)回滾段, 未創(chuàng)建其它回滾段
B. 只創(chuàng)建了PRIVATE回滾段, 但INITsid.ORA的ROLLBACK_SEGMENTS中未列出這些回滾段
C. 創(chuàng)建了PUBLIC回滾段, 但這些回滾段都處于OFFLINE狀態(tài)
解決方法: 根據(jù)以上原因相應(yīng)解決即可
(3)
ORA_01555 snapshot too old: rollback segment number string with name "string" too small
原因可分為以下情形:
A. 回滾段太少/太小
數(shù)據(jù)庫中有太多的事務(wù)修改數(shù)據(jù)并提交, 就會發(fā)生已提交事務(wù)曾使用的空間被重用, 從而造成一個延
續(xù)時間長的查詢所請求的數(shù)據(jù)已經(jīng)不在回滾段中.
解決方法: 創(chuàng)建更多的回滾段, 為回滾段設(shè)置較大的EXTENT以及較大的MINEXTENTS
B. 回滾段被破壞
由于回滾段被破壞, 造成事務(wù)無法將修改前的內(nèi)容(read-consistent snapshot) 放入回滾段, 也會產(chǎn)生ORA-01555錯誤.
解決方法: 將被破壞的回滾段OFFLINE, 刪除重建.
C. FETCH ACROSS COMMIT
當(dāng)一個進程打開一個CURSOR, 然后循環(huán)執(zhí)行FETCH, UPDATE, COMMIT, 如果更新的表與FETCH的是同一個表, 就很可能發(fā)生ORA-01555錯誤.
解決方法:
a. 使用大的回滾段
b. 減少提交頻率(可參見本論壇”怎么樣避免一個PROCEDURE被重復(fù)調(diào)用”一貼中, 無名朋友的回帖)
以上兩種方法只能減少該錯誤發(fā)生的可能, 不能完全避免. 如果要完全避免, 須從執(zhí)行方法著手, 可以用以下兩種方法:
c. 建立一個臨時表, 存放要更新的表的查詢列(如主鍵及相關(guān)的條件列), 從臨時表FETCH, 更新原來的表.
d. 捕獲ORA-01555錯誤, 關(guān)閉并重新打開CURSOR, 繼續(xù)執(zhí)行循環(huán):
示例(示例程序的思路來源自O(shè)RACLE的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用來提高寫性能的一種機制:當(dāng)修改操作(INSERT/UPDATE/DELETE)發(fā)生時, ORACLE將原有的內(nèi)容寫入回滾段, 更新每個數(shù)據(jù)塊的頭部使其指向相應(yīng)的回滾段,當(dāng)該操作被COMMIT時, ORACLE并不再重新訪問一遍所有的數(shù)據(jù)塊來確認所有的修改,而只是更新位于回滾段頭部的事務(wù)槽來指明該事務(wù)已被COMMIT,這使得寫操作可以很快結(jié)束從而提高了性能接下來的任何訪問該操作所修改的數(shù)據(jù)的操作會使先前的寫操作真正生效, 從而訪問到新的值. Delayedlogging block cleanout 雖然提高了性能, 但卻可能導(dǎo)致ORA-01555. 這種情況下,在OPEN/FETCH前對該表做全表掃描(保證所有的修改被確認)會有所幫助.
* 不適當(dāng)?shù)腛PTIMAL參數(shù): 太小的OPTIMAL參數(shù)會使回滾段很快被SHRINK, 造成后續(xù)讀取操作訪問時, 先前的內(nèi)容已丟失. 仔細設(shè)計OPTIMAL參數(shù), 不要讓回滾段過于頻繁的EXTEND/SHRINK有助于問題的解決.
* DB BLOCK BUFFER太小: 如果讀一致性所請求的塊的先前內(nèi)容在緩沖區(qū)中, 那么就不用去訪問回滾段. 而如果緩沖區(qū)太小,使得先前版本的內(nèi)容在CACHE中的可能性變小, 從而必須頻繁的訪問回滾段來獲取先前的內(nèi)容, 這將大大增大ORA-01555發(fā)生的可能.