Email: service@parnassusdata.com 7 x 24 online support!

Oracle DBMS_REPAIRパッケージの使用例

Oracle DBMS_REPAIRパッケージの使用例

ORACLEデータベース によくあるエラ の解決策

プロのOracle Databaseの復旧サービスを提供
携帯番号: +86 13764045638 メール:service@parnassusdata.com

 
 
[質問]
DBMS_REPAIRパッケージの使用方法について障害発生からの手順を踏まえて教えてください。

[回答]
データブロック破損の障害が発生した場合は、適切なバックアップからリカバリを行い対
応するのが原則です。

しかし、運用のミスなどによりリカバリが行えない場合、DBMS_REPAIRパッケージにより
破損ブロックを読み飛ばすように設定することができます。

※ DBMS_REPAIRパッケージは破損したデータを修復するものではありません。以下の例で
   も失われるデータがあります。


[実施環境]

<表定義>

  SQL> create table test (c1 number, c2 char(100));
  SQL> begin
         for i in 1..1000 loop
           insert into test values (i, i);
           commit;
         end loop;
       end;
       /
  SQL> create index i_test on test(c1);

[障害発生]

(1)障害発生

  SQL> select * from test where c1 = 1;
  select * from test where c1 = 1
                *
  1行でエラーが発生しました。
  ORA-01578: ファイル番号 5,ブロック番号
  275でOracleデータ・ブロックに障害が発生しました。
  ORA-01110: データ・ファイル 5 :

  SQL> analyze table test validate structure cascade;
  analyze table test validate structure cascade
  *
  1行でエラーが発生しました。
  ORA-01578: ファイル番号 5,ブロック番号
  275でOracleデータ・ブロックに障害が発生しました。
  ORA-01110: データ・ファイル 5 :

(2)Repair Table/Orphan Tableの作成

  ※ まず、障害状況を捕捉するための表(REPAIR_TABLE/ORPHAN_KEY_TABLE)を作成します。

  SQL> connect sys/<sys_password>
  SQL> begin
         dbms_repair.admin_tables (
           table_name => 'REPAIR_TABLE',
           table_type => dbms_repair.repair_table,
           action     => dbms_repair.create_action,
           tablespace => 'USERS');
       end;
       /

  SQL> begin
         dbms_repair.admin_tables (
           table_name => 'ORPHAN_KEY_TABLE',
           table_type => dbms_repair.orphan_table,
           action     => dbms_repair.create_action,
           tablespace => 'USERS');
       end;
       /

(3)破損オブジェクトの確認

  ※ dbms_repair.check_objectにより指定したオブジェクトの検証を行い、破損状況お
     よび修復指示に関する情報を指定した表(REPAIR_TABLE)に格納します。

  SQL> set serveroutput on
  SQL> declare num_corrupt INT;
       begin
         num_corrupt := 0;
         dbms_repair.check_object (
           schema_name => 'TEST',
           object_name => 'TEST',
           repair_table_name => 'REPAIR_TABLE',
           corrupt_count => num_corrupt);
         dbms_output.put_line('num :'|| to_char(num_corrupt));
       end;
       /

  num :1

  ※ 上記実行結果より1つのデータブロックが破損していることを確認できました。
     次に、破損状況等をREPAIR_TABLEから確認します。

  SQL> select object_name, block_id, corrupt_type, marked_corrupt,
       corrupt_description, repair_description
       from repair_table;

  OBJECT_NAME                      BLOCK_ID CORRUPT_TYPE MARKED_COR
  ------------------------------ ---------- ------------ ----------
  CORRUPT_DESCRIPTION
  --------------------------------------------------------------------------------
  REPAIR_DESCRIPTION
  --------------------------------------------------------------------------------
  TEST                                  275         6148 FALSE
  
  mark block software corrupt

(4)破損ブロックの修正(対象データブロックに破損マークをつけます)

  SQL> set serveroutput on
  SQL> declare num_fix INT;
       begin
         num_fix := 0;
         dbms_repair.fix_corrupt_blocks (
           schema_name => 'TEST',
           object_name => 'TEST',
           object_type => dbms_repair.table_object,
           repair_table_name => 'REPAIR_TABLE',
           fix_count => num_fix);
         dbms_output.put_line('num fixed :'|| to_char(num_fix));
       end;
       /

  num fixed :1

  PL/SQLプロシージャが正常に完了しました。

(5)破損マークがついたことの確認

  SQL> select object_name, block_id, corrupt_type, marked_corrupt,
       corrupt_description, repair_description
       from repair_table;

  OBJECT_NAME                      BLOCK_ID CORRUPT_TYPE MARKED_COR
  ------------------------------ ---------- ------------ ----------
  CORRUPT_DESCRIPTION
  --------------------------------------------------------------------------------
  REPAIR_DESCRIPTION
  --------------------------------------------------------------------------------
  TEST                                  275         6148 TRUE
  
  mark block software corrupt

  ※ MARKED_CORRUPT列がTRUEにかわったことが確認できます。

(6)破損データブロック関連の索引エントリの確認

  SQL> set serveroutput on
  SQL> declare num_orphans INT;
       begin
         num_orphans := 0;
         dbms_repair.dump_orphan_keys (
           schema_name => 'TEST',
           object_name => 'I_TEST',
           object_type => dbms_repair.index_object,
           repair_table_name => 'REPAIR_TABLE',
           orphan_table_name => 'ORPHAN_KEY_TABLE',
           key_count => num_orphans);
         dbms_output.put_line('orphan key count :'|| to_char(num_orphans));
       end;
       /

  orphan key count :7

  PL/SQLプロシージャが正常に完了しました。

  ※ 上記のとおり破損ブロックに対応する索引エントリが7つ存在することを確認できま
     す。このように破損ブロックに対応する索引エントリが存在する場合は索引の再作
     成が必要となります。(手順(8))

(7)対象オブジェクトのスキップ指定

  破損ブロックに破損マークをつけただけではまだ検索時に以下のエラーが発生します。
  スキップ指定することで対象オブジェクトへのアクセスを可能にします。

  SQL> select * from test.test where c1 = 1;
  select * from test.test where c1 = 1
                     *
  1行でエラーが発生しました。
  ORA-01578: ファイル番号 5,ブロック番号
  275でOracleデータ・ブロックに障害が発生しました。
  ORA-01110: データ・ファイル 5 :

  SQL> begin
         dbms_repair.skip_corrupt_blocks (
           schema_name => 'TEST',
           object_name => 'TEST',
           object_type => dbms_repair.table_object,
           flags => dbms_repair.skip_flag);
       end;
       /

  PL/SQLプロシージャが正常に完了しました。

  SQL> select table_name, skip_corrupt from dba_tables
       where owner='TEST' and table_name = 'TEST';

  TABLE_NAME                     SKIP_COR
  ------------------------------ --------
  TEST                           ENABLED

  以上により対象オブジェクトへのアクセスが可能になりますが、破損マークがつけられ、
  検索時にスキップしたブロックに格納されているデータは読み飛ばされていることを以
  下よりも確認できます。

  SQL> select count(*) from test.test;

  COUNT(*)
  ----------
         993
  (当初1000件のデータを格納していますので7件のデータが失われたことを意味します。)

(8)索引の再作成

  SQL> alter index test.i_test rebuild online;

  索引が変更されました。

(9)フリーリストの再編成

  SQL> begin
         dbms_repair.rebuild_freelists (
           schema_name => 'TEST',
           object_name => 'TEST',
           object_type => dbms_repair.table_object);
       end;
       /

  PL/SQLプロシージャが正常に完了しました。

  自動セグメント領域管理の場合は(9)のオペレーションは不要となります。
  自動セグメント領域管理の場合にて(9)のオペレーションを実施した場合は
  ORA-10614 が発生致します。ただしこのエラーは無視して頂いて問題ありま
  せん。


[参考資料]
『Oracle8i 管理者ガイド』20章 データ・ブロック破損への対処 
『Oracle9i 管理者ガイド』22章 データ・ブロック破損の検出と修復
『Oracle8i PL/SQL パッケージ・プロシージャリファレンス』36章 DBMS_REPAIR
『Oracle9i PL/SQL パッケージ・プロシージャリファレンス』47章 DBMS_REPAIR