使用DBMS_REPAIR包修復(fù)壞塊(二)
?
??? 昨天簡單得了解了一下關(guān)于數(shù)據(jù)塊損壞后該如何操作,都是一些理論知識,當(dāng)然理論知識也還沒有學(xué)完
。今天來繼續(xù)學(xué)習(xí)理論知識,并且在完成之后找一個(gè)實(shí)例來實(shí)踐一下。好,下面開始。
--------------------------------------
?
?
二、評估使用DBMS_REPAIR的損益
?
??? 要判斷損益,需要了解一下問題:
?
??? 1、損壞的盤區(qū)是什么?
?
??? 這一步比較簡單,執(zhí)行CHECK_OBJECT過程,然后查詢修復(fù)表即可。
?
??? 2、其他可用于處理數(shù)據(jù)損壞的方法是什么?
?
??? 需要考慮以下幾種方法:
??? * 假設(shè)可以從另一數(shù)據(jù)源獲得數(shù)據(jù),則刪除、重建、并填充該對象。
??? * 對損壞的表發(fā)布CREATE TABLE ... AS SELECT語句,以重建新表
??? * 通過從選取(select)語句來排除損壞的行來忽略損壞
??? * 執(zhí)行介質(zhì)恢復(fù)
?
??? 3、當(dāng)使用DBMS_REPAIR來使一個(gè)對象可用時(shí),會引入什么邏輯矛盾或副作用?并考慮代價(jià)
?
??? 主要可能會有以下問題:
??? * 標(biāo)記損壞的數(shù)據(jù)塊中的行會無法訪問。
??? * 有可能破壞參照完整性約束,如有則需要停用
??? * 如果在表上定義了觸發(fā)器,要考慮如果刪除、重新插入數(shù)據(jù)是否會觸發(fā)
??? * 空閑列表數(shù)據(jù)塊可能不可訪問。
??????? 如果損壞數(shù)據(jù)塊在空閑列表的頭部或尾部,則空間管理會重新初始化該空閑列表。
??????? 可能會存在該放入空閑列表但有沒有放入的數(shù)據(jù)塊,運(yùn)行REBUILD_FREELISTS解決這個(gè)問題。
??? * 索引和表不同步了。需要執(zhí)行DUMP_ORPHAN_KEYS獲得信息,然后用ALTER INDEX ... REBUILD ONLINE同步
?
??? 4、如果修復(fù)中丟失了數(shù)據(jù),這些數(shù)據(jù)還能被檢索碼?
?
??? 當(dāng)數(shù)據(jù)庫被標(biāo)記為損壞時(shí),仍可以從索引中檢索數(shù)據(jù)。DUMP_ORPHAN_KEYS過程可以有助于檢索該信息。當(dāng)然這種方法檢索數(shù)據(jù)取決于索引和表之間數(shù)據(jù)冗余的數(shù)量。
?
?
?
三、使對象可用
?
??? 1、損壞修復(fù)(使用FIX_CORRUPT_BLOCKS和SKIP_CORRUPT_BLOCKS)
?
??? 通過建立一個(gè)環(huán)境,跳過DBMS_REPAIR修復(fù)能力范圍之外的損壞,使損壞對象可用。如果該損壞包括了數(shù)據(jù)丟失,如數(shù)據(jù)塊中的壞行,所有這樣的數(shù)據(jù)塊都被FIX_CORRUPT_BLOCKS過程標(biāo)記為損壞。然后運(yùn)行SKIP_CORRUPT_BLOCKS跳過對象中被標(biāo)記為損壞的數(shù)據(jù)塊。當(dāng)設(shè)置跳過后,表和索引掃描就跳過所有被標(biāo)記成損壞的數(shù)據(jù)塊,這適用于介質(zhì)和軟件損壞數(shù)據(jù)塊兩者。
?
??? 2、跳過損壞數(shù)據(jù)塊時(shí)的意義
?
??? 如果索引和表不同步了,那么當(dāng)一個(gè)查詢僅僅探查索引,而下一個(gè)查詢探查索引和表兩者時(shí),SET TRANSACTION READ ONLY事務(wù)就可能有矛盾。如果表數(shù)據(jù)塊被標(biāo)記成損壞,那么兩個(gè)查詢就會返回不同的結(jié)果,這就破壞了只讀事務(wù)的規(guī)則。
??? 處理這個(gè)問題的一個(gè)方法是在SET TRANSACTION READ ONLY事務(wù)中不跳過損壞數(shù)據(jù)塊。當(dāng)選取被鏈接在一起的行時(shí)也會發(fā)生相同的問題,本質(zhì)上說,對相同行的查詢既可以又不可以訪問損壞數(shù)據(jù)塊,因此產(chǎn)生不同結(jié)果
?
?
?
四、修復(fù)損壞和重建丟失的數(shù)據(jù)
?
??? 1、用DUMP_ORPHAN_KEYS過程恢復(fù)數(shù)據(jù)
?
??? DUMP_ORPHAN_KEYS過程報(bào)告指向損壞數(shù)據(jù)塊中的行的索引項(xiàng)。所有這些索引項(xiàng)都被插入到一個(gè)孤立鍵表中,該表存儲了損壞數(shù)據(jù)塊的鍵和行標(biāo)識。索引出了索引項(xiàng)信息之后,就可以使用ALTER INDEX ... REBUILD ONLINE語句重建該索引。
?
??? 2、用REBUILD_FREELISTS過程修復(fù)空閑列表
?
??? 如果是空閑列表(SEGMENT SPACE MANAGEMENT MANUAL)來管理段中的空閑空間時(shí),就使用該過程。
?
??? 當(dāng)在空閑列表的頭部或尾部找到了被標(biāo)記為“損壞”的數(shù)據(jù)塊時(shí),將重新初始化空閑列表,并返回一個(gè)錯(cuò)誤。這樣雖然從空閑列表中清除了錯(cuò)誤數(shù)據(jù)塊,但是它使得空閑列表不能訪問緊跟損壞數(shù)據(jù)塊之后的所有數(shù)據(jù)塊,此時(shí)可以使用REBUILD_FREELISTS過程來重新初始化空閑列表。
此時(shí)對象會被掃描,若適合作為空閑列表上的數(shù)據(jù)塊,則增加到這里面。
?
??? 3、用SEGMENT_FIX_STATUS過程修復(fù)段位圖
?
??? 對于用位圖(SEGMENT SPACE MANAGEMENT AUTO)來管理段中的空閑空間時(shí),使用這個(gè)過程。這個(gè)過程或者基于對應(yīng)的數(shù)據(jù)塊的當(dāng)前內(nèi)容重新計(jì)算位圖的狀態(tài),或者指定將位圖項(xiàng)設(shè)置成特殊的值。通常,狀態(tài)被正確得中心計(jì)算而不需要強(qiáng)行設(shè)置。
?
?
?
五、示例
?
---------------------------------------------
-- 首先用ADMIN_TABLES建立修復(fù)表/孤立鍵表
-- 修復(fù)表用于表示錯(cuò)誤數(shù)據(jù)塊以及修復(fù)方法
-- 修復(fù)表 -> FIX_CORRUPT_BLOCKS
-- 孤立鍵表 -> DUMP_ORPHAN_KEYS
---------------------------------------------
-- 首先用ADMIN_TABLES建立修復(fù)表/孤立鍵表
-- 修復(fù)表用于表示錯(cuò)誤數(shù)據(jù)塊以及修復(fù)方法
-- 修復(fù)表 -> FIX_CORRUPT_BLOCKS
-- 孤立鍵表 -> DUMP_ORPHAN_KEYS
---------------------------------------------
?
--先來建立修復(fù)表
begin
? dbms_repair.admin_tables(table_name => 'REPAIR_WXQ',
?????????????????????????? table_type => dbms_repair.repair_table,
?????????????????????????? action???? => dbms_repair.create_action,
?????????????????????????? tablespace => 'WXQ_TBS2');
end;
/
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????????????????????????
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????????????????????????
?
-- 用同樣的過程創(chuàng)建孤立鍵表
begin
? dbms_repair.admin_tables(table_name => 'ORPHAN_WXQ',
?????????????????????????? table_type => dbms_repair.orphan_table,
?????????????????????????? action???? => dbms_repair.create_action,
?????????????????????????? tablespace => 'WXQ_TBS2');
end;
/
begin
? dbms_repair.admin_tables(table_name => 'ORPHAN_WXQ',
?????????????????????????? table_type => dbms_repair.orphan_table,
?????????????????????????? action???? => dbms_repair.create_action,
?????????????????????????? tablespace => 'WXQ_TBS2');
end;
/
?
--同樣來查看一下表結(jié)構(gòu)
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??????????????????????????????????
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來檢查損壞數(shù)量
-- 注意:最終輸出為一個(gè)int型數(shù)字
---------------------------------------------
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;
/
?
-- 查看修復(fù)表
select a.object_name,
?????? a.block_id,
?????? a.corrupt_type,
?????? a.marked_corrupt,
?????? a.corrupt_description,
?????? a.repair_description
? from repair_wxq a;
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??????????????? ....?????????????? ....
----------- -------- ------------ ---------- ------------------- ------------------
???????? T1??????? 3??????????? 1????? FALSE??????????????? ....?????????????? ....
?
---------------------------------------------
-- 使用FIX_CORRUPT_BLOCKS來修理損壞數(shù)據(jù)塊
--
---------------------------------------------
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;
/
?
--確認(rèn)已做修復(fù)
select a.object_name, a.block_id, a.marked_corrupt
? from repair_wxq a;
select a.object_name, a.block_id, a.marked_corrupt
? from repair_wxq a;
?
OBJECT_NAME BLOCK_ID MARKED_COR
----------- -------- ----------
???????? T1??????? 3????? FALSE
----------- -------- ----------
???????? T1??????? 3????? FALSE
?
----------------------------------------------------
-- 使用DUMP_ORPHAN_KEYS來查找指向損壞數(shù)據(jù)塊的指引項(xiàng)
--
----------------------------------------------------
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;
/
?
--查看該表狀態(tài)
select owner, table_name, skip_corrupt
? from dba_tables
where table_name = 'T1';
select owner, table_name, skip_corrupt
? from dba_tables
where table_name = 'T1';
?
?
?
?
?