DBMS_REPAIR

abstractcyj發表於2014-08-19

今日學習了楊版主的資料恢復的關於DBMS_REPAIR的內容。



dbms_repair包的工作原理比較簡單,是將檢測到的壞塊標註出來,使隨後的DML操作跳過該塊,同時,DBMS_REPAIR包還提供了用於儲存索引中的包含的標註為壞塊中的鍵值,以及修復
freelist和segment bitmap的過程。

構建測試環境。表空間資料檔案只有1M,因為要修改資料檔案模擬資料庫資訊。
create tablespace mytest datafile 'E:\data\oradata\test.dbf' size 1m extent management local autoallocate segment space management manual;

alter user scott quota unlimited on mytest;

alter user scott account unlock identified by tiger;

insert into test select object_id, object_name from sys.dba_objects
where rownum <= 10000;

通過UltraEdit修改了資料檔案,使得查詢報錯。
修改之後,必須重啟資料庫,因為oracle使用buffer cache來滿足查詢



接下來開始修復的過程:
1. 建立REPAIR_TABLE與ORPHAN_KEY_TABLE, REPAIR_TABLE用來記錄錯誤檢查結果,ORPHAN_KEY_TABLE用來記錄表壞塊中記錄在索引對應鍵值。
BEGIN
  sys.dbms_repair.admin_tables(table_name => 'REPAIR_TABLE',
                               table_type => sys.dbms_repair.repair_table,
                               action     => sys.dbms_repair.create_action,
                               tablespace => 'USERS');
END;

BEGIN
  sys.dbms_repair.admin_tables(table_name => 'ORPHAN_KEY_TABLE',
                               table_type => sys.dbms_repair.ORPHAN_TABLE,
                               action     => sys.dbms_repair.create_action,
                               tablespace => 'USERS');
END;
2. 使用CHECK_OBJECT過程檢測壞塊

DECLARE
  v_num_corrupt NUMBER := 0;
BEGIN
  sys.dbms_repair.check_object(schema_name       => 'SCOTT',
                               object_name       => 'TEST',
                               repair_table_name => 'REPAIR_TABLE',
                               corrupt_count     => v_num_corrupt);
  dbms_output.put_line('corrupted block:' || v_num_corrupt);
END;



3. 使用DUMP_ORPHAN_KEYS過程來儲存壞塊中的鍵值。問題:表出現了壞塊,但是索引沒有損壞,通過表掃描仍然出現錯誤,但是通過索引掃描仍然可以返回結果,
這會造成資料的不一致性。通過DUMP_ORPHAN_KEYS過程來儲存壞塊中的索引鍵值,這樣當執行完SKIP_CORRUPT_BLOCKS操作後就能重新建立索引了。
DECLARE
  v_orphan_num NUMBER;
BEGIN
  sys.dbms_repair.dump_orphan_keys(schema_name       =>'SCOTT',
                                   object_name       => 'INDX_TEST1',
                                   repair_table_name =>'REPAIR_TABLE',
                                   orphan_table_name =>'ORPHAN_KEY_TABLE',
                                   key_count         =>v_orphan_num);
                                   
  dbms_output.put_line(v_orphan_num);
END;




DECLARE
  v_orphan_num NUMBER;
BEGIN
  sys.dbms_repair.dump_orphan_keys(schema_name       =>'SCOTT',
                                   object_name       => 'INDX_TEST2',
                                   repair_table_name =>'REPAIR_TABLE',
                                   orphan_table_name =>'ORPHAN_KEY_TABLE',
                                   key_count         =>v_orphan_num);
                                   
  dbms_output.put_line(v_orphan_num);
END;

注意對每個索引都要執行DUMP_ORPHAN_KEYS過程
4. 使用REBUILD_FREELISTS過程來修改FREELISTS
如果壞塊發生在FREELISTS列表中的中部,則FREELISTS列表後面的塊都無法訪問,在這個測試中,錯誤是人為產生的,清楚知道錯誤並不在FREELISTS中,因此可以跳過此步驟,一般情況下,無法定位壞塊位置,則需要執行該過程。
BEGIN
  sys.dbms_repair.rebuild_freelists(schema_name => 'SCOTT',
                                    object_name => 'TEST',
                                    object_type => sys.dbms_repair.table_object);
END;

5. 執行SKIP_CORRUPT_BLOCKS過程,使後續DML操作跳過壞塊
BEGIN
  sys.dbms_repair.skip_corrupt_blocks(schema_name => 'SCOTT',
                                      object_name => 'TEST',
                                      object_type => sys.dbms_repair.table_object);
END;


經過這個步驟之後,表已經可以訪問。但是ID=123的那條記錄已丟失。

6. 經過步驟5之後,資料與索引仍然存在不一致的問題,因此必須重建索引。
需要注意的是,重建索引一定要先DROP,然後再CREATE,使用REBUILD的方式,重建的資料來源來自索引。仍然會導致問題的產生

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