使用DBMS_REPAIR包修復壞塊(二)
?
??? 昨天簡單得了解了一下關于數據塊損壞后該如何操作,都是一些理論知識,當然理論知識也還沒有學完
。今天來繼續學習理論知識,并且在完成之后找一個實例來實踐一下。好,下面開始。
--------------------------------------
?
?
二、評估使用DBMS_REPAIR的損益
?
??? 要判斷損益,需要了解一下問題:
?
??? 1、損壞的盤區是什么?
?
??? 這一步比較簡單,執行CHECK_OBJECT過程,然后查詢修復表即可。
?
??? 2、其他可用于處理數據損壞的方法是什么?
?
??? 需要考慮以下幾種方法:
??? * 假設可以從另一數據源獲得數據,則刪除、重建、并填充該對象。
??? * 對損壞的表發布CREATE TABLE ... AS SELECT語句,以重建新表
??? * 通過從選取(select)語句來排除損壞的行來忽略損壞
??? * 執行介質恢復
?
??? 3、當使用DBMS_REPAIR來使一個對象可用時,會引入什么邏輯矛盾或副作用?并考慮代價
?
??? 主要可能會有以下問題:
??? * 標記損壞的數據塊中的行會無法訪問。
??? * 有可能破壞參照完整性約束,如有則需要停用
??? * 如果在表上定義了觸發器,要考慮如果刪除、重新插入數據是否會觸發
??? * 空閑列表數據塊可能不可訪問。
??????? 如果損壞數據塊在空閑列表的頭部或尾部,則空間管理會重新初始化該空閑列表。
??????? 可能會存在該放入空閑列表但有沒有放入的數據塊,運行REBUILD_FREELISTS解決這個問題。
??? * 索引和表不同步了。需要執行DUMP_ORPHAN_KEYS獲得信息,然后用ALTER INDEX ... REBUILD ONLINE同步
?
??? 4、如果修復中丟失了數據,這些數據還能被檢索碼?
?
??? 當數據庫被標記為損壞時,仍可以從索引中檢索數據。DUMP_ORPHAN_KEYS過程可以有助于檢索該信息。當然這種方法檢索數據取決于索引和表之間數據冗余的數量。
?
?
?
三、使對象可用
?
??? 1、損壞修復(使用FIX_CORRUPT_BLOCKS和SKIP_CORRUPT_BLOCKS)
?
??? 通過建立一個環境,跳過DBMS_REPAIR修復能力范圍之外的損壞,使損壞對象可用。如果該損壞包括了數據丟失,如數據塊中的壞行,所有這樣的數據塊都被FIX_CORRUPT_BLOCKS過程標記為損壞。然后運行SKIP_CORRUPT_BLOCKS跳過對象中被標記為損壞的數據塊。當設置跳過后,表和索引掃描就跳過所有被標記成損壞的數據塊,這適用于介質和軟件損壞數據塊兩者。
?
??? 2、跳過損壞數據塊時的意義
?
??? 如果索引和表不同步了,那么當一個查詢僅僅探查索引,而下一個查詢探查索引和表兩者時,SET TRANSACTION READ ONLY事務就可能有矛盾。如果表數據塊被標記成損壞,那么兩個查詢就會返回不同的結果,這就破壞了只讀事務的規則。
??? 處理這個問題的一個方法是在SET TRANSACTION READ ONLY事務中不跳過損壞數據塊。當選取被鏈接在一起的行時也會發生相同的問題,本質上說,對相同行的查詢既可以又不可以訪問損壞數據塊,因此產生不同結果
?
?
?
四、修復損壞和重建丟失的數據
?
??? 1、用DUMP_ORPHAN_KEYS過程恢復數據
?
??? DUMP_ORPHAN_KEYS過程報告指向損壞數據塊中的行的索引項。所有這些索引項都被插入到一個孤立鍵表中,該表存儲了損壞數據塊的鍵和行標識。索引出了索引項信息之后,就可以使用ALTER INDEX ... REBUILD ONLINE語句重建該索引。
?
??? 2、用REBUILD_FREELISTS過程修復空閑列表
?
??? 如果是空閑列表(SEGMENT SPACE MANAGEMENT MANUAL)來管理段中的空閑空間時,就使用該過程。
?
??? 當在空閑列表的頭部或尾部找到了被標記為“損壞”的數據塊時,將重新初始化空閑列表,并返回一個錯誤。這樣雖然從空閑列表中清除了錯誤數據塊,但是它使得空閑列表不能訪問緊跟損壞數據塊之后的所有數據塊,此時可以使用REBUILD_FREELISTS過程來重新初始化空閑列表。
此時對象會被掃描,若適合作為空閑列表上的數據塊,則增加到這里面。
?
??? 3、用SEGMENT_FIX_STATUS過程修復段位圖
?
??? 對于用位圖(SEGMENT SPACE MANAGEMENT AUTO)來管理段中的空閑空間時,使用這個過程。這個過程或者基于對應的數據塊的當前內容重新計算位圖的狀態,或者指定將位圖項設置成特殊的值。通常,狀態被正確得中心計算而不需要強行設置。
?
?
?
五、示例
?
---------------------------------------------
-- 首先用ADMIN_TABLES建立修復表/孤立鍵表
-- 修復表用于表示錯誤數據塊以及修復方法
-- 修復表 -> FIX_CORRUPT_BLOCKS
-- 孤立鍵表 -> DUMP_ORPHAN_KEYS
---------------------------------------------
?
--先來建立修復表
begin
? dbms_repair.admin_tables(table_name => 'REPAIR_WXQ',
?????????????????????????? table_type => dbms_repair.repair_table,
?????????????????????????? action???? => dbms_repair.create_action,
?????????????????????????? tablespace => 'WXQ_TBS2');
end;
/
?
--查看一下
SQL> desc REPAIR_WXQ
Name??????????????? Type?????????? Nullable Default Comments
------------------- -------------- -------- ------- --------
OBJECT_ID?????????? NUMBER??????????????????????????????????
TABLESPACE_ID?????? NUMBER??????????????????????????????????
RELATIVE_FILE_ID??? NUMBER??????????????????????????????????
BLOCK_ID??????????? NUMBER??????????????????????????????????
CORRUPT_TYPE??????? NUMBER??????????????????????????????????
SCHEMA_NAME???????? VARCHAR2(30)????????????????????????????
OBJECT_NAME???????? VARCHAR2(30)????????????????????????????
BASEOBJECT_NAME???? VARCHAR2(30)?? Y????????????????????????
PARTITION_NAME????? VARCHAR2(30)?? Y????????????????????????
CORRUPT_DESCRIPTION VARCHAR2(2000) Y????????????????????????
REPAIR_DESCRIPTION? VARCHAR2(200)? Y????????????????????????
MARKED_CORRUPT????? VARCHAR2(10)????????????????????????????
CHECK_TIMESTAMP???? DATE????????????????????????????????????
FIX_TIMESTAMP?????? DATE?????????? Y????????????????????????
REFORMAT_TIMESTAMP? DATE?????????? Y????????????????????????
?
-- 用同樣的過程創建孤立鍵表
begin
? dbms_repair.admin_tables(table_name => 'ORPHAN_WXQ',
?????????????????????????? table_type => dbms_repair.orphan_table,
?????????????????????????? action???? => dbms_repair.create_action,
?????????????????????????? tablespace => 'WXQ_TBS2');
end;
/
?
--同樣來查看一下表結構
SQL> desc ORPHAN_WXQ
Name?????????? Type???????? Nullable Default Comments
-------------- ------------ -------- ------- --------
SCHEMA_NAME??? VARCHAR2(30)??????????????????????????
INDEX_NAME???? VARCHAR2(30)??????????????????????????
IPART_NAME???? VARCHAR2(30) Y????????????????????????
INDEX_ID?????? NUMBER????????????????????????????????
TABLE_NAME???? VARCHAR2(30)??????????????????????????
PART_NAME????? VARCHAR2(30) Y????????????????????????
TABLE_ID?????? NUMBER????????????????????????????????
KEYROWID?????? UROWID(4000)??????????????????????????
KEY??????????? UROWID(4000)??????????????????????????
DUMP_TIMESTAMP DATE??????????????????????????????????
?
?
?
---------------------------------------------
-- 接著用CHECK_OBJECT來檢查損壞數量
-- 注意:最終輸出為一個int型數字
---------------------------------------------
declare
? num_corrupt int := 0;
begin
? dbms_repair.check_object(schema_name?????? => 'WANGXIAOQI',
?????????????????????????? object_name?????? => 'T1',
?????????????????????????? repair_table_name => 'REPAIR_WXQ',
?????????????????????????? corrupt_count???? => num_corrupt);
? dbms_output.put_line('number corrupt: ' || to_char(num_corrupt));
end;
/
?
-- 查看修復表
select a.object_name,
?????? a.block_id,
?????? a.corrupt_type,
?????? a.marked_corrupt,
?????? a.corrupt_description,
?????? a.repair_description
? from repair_wxq a;
?
OBJECT_NAME BLOCK_ID CORRUPT_TYPE MARKED_COR CORRUPT_DESCRIPTION REPAIR_DESCRIPTION
----------- -------- ------------ ---------- ------------------- ------------------
???????? T1??????? 3??????????? 1????? FALSE??????????????? ....?????????????? ....
?
---------------------------------------------
-- 使用FIX_CORRUPT_BLOCKS來修理損壞數據塊
--
---------------------------------------------
declare
? num_fix int := 0;
begin
? dbms_repair.fix_corrupt_blocks(schema_name?????? => 'WANGXIAOQI',
???????????????????????????????? object_name?????? => 'T1',
???????????????????????????????? object_type?????? => dbms_repair.table_object,
???????????????????????????????? repair_table_name => 'REPAIR_WXQ',
???????????????????????????????? fix_count???? => num_fix);
? dbms_output.put_line('num fix: ' || to_char(num_fix));
end;
/
?
--確認已做修復
select a.object_name, a.block_id, a.marked_corrupt
? from repair_wxq a;
?
OBJECT_NAME BLOCK_ID MARKED_COR
----------- -------- ----------
???????? T1??????? 3????? FALSE
?
----------------------------------------------------
-- 使用DUMP_ORPHAN_KEYS來查找指向損壞數據塊的指引項
--
----------------------------------------------------
declare
? num_orphans int := 0;
begin
? dbms_repair.dump_orphan_keys(schema_name?????? => 'WANGXIAOQI',
?????????????????????????????? object_name?????? => 'T1_PK',
?????????????????????????????? object_type?????? => dbms_repair.index_object,
?????????????????????????????? repair_table_name => 'REPAIR_WXQ',
?????????????????????????????? orphan_table_name => 'ORPHAN_WXQ',
?????????????????????????????? key_count???????? => num_orphans);
? dbms_output.put_line('orphan key count: ' || to_char(num_orphans));
end;
/
?
---------------------------------------------
-- 使用REBUILD_FREELISTS重建空閑列表
--
---------------------------------------------
begin
? dbms_repair.rebuild_freelists(schema_name => 'WANGXIAOQI',
??????????????????????????????? object_name => 'T1',
??????????????????????????????? object_type => dbms_repair.table_object);
end;
/
?
---------------------------------------------
-- 使用SKIP_CORRUPT_BLOCKS控制是否跳過壞塊
--
---------------------------------------------
begin
? dbms_repair.skip_corrupt_blocks(schema_name => 'WANGXIAOQI',
????????????????????????????????? object_name => 'T1',
????????????????????????????????? object_type => dbms_repair.table_object,
????????????????????????????????? flags?????? => dbms_repair.SKIP_FLAG);
end;
/
?
--查看該表狀態
select owner, table_name, skip_corrupt
? from dba_tables
where table_name = 'T1';
?
?
?
?
?