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

    You are here

Oracle ORA-8102の主な発生原因とその対処方法について

Oracle ORA-8102の主な発生原因とその対処方法について

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

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

 
 
[エラー・メッセージ]

ORA-08102 索引キーは見つかりません (オブジェクト番号 string、dba string(string))
------------------------------------------------------------------------------- 
原因:内部エラーです。索引に不一致があります。
対処:トレース・ファイルをエラーの再現についての情報とともに、オラクル社カスタマ・
   サポート・センターへ送付してください。

[技術的説明]

- エラー内容説明

表データが更新される際に、その表に索引が設定されていれば同時にその索引の情報も更
新されなければなりません。表データと索引キーは常に同期していなければなりません。
Oracleでは索引に対する操作を行う際に、索引キーと表に格納されている行データの不整
性チェックを行います。ORA-8102エラーは、このチェックにおいて表に格納されている行
データと、それに対応する索引キーの状態が不整合であることを検知して発生させている
エラーです。

- エラー発生原因

障害を引き起こす要因は様々ですが、代表的な発生原因としてはシステムクラッシュによ
りディスクに書き込まれたデータ異常により発生することがあります。

  - システムクラッシュ
  - 不具合
    - Oracleに起因する不具合
    - OSに起因する不具合
    - H/W(CPU、メモリ、Diskコントローラーなど)に起因する不具合
    - Volume Manager
    - その他

また、以下のとおり索引が損傷を受けている場合、表自体のデータが損傷を受けている場
合が考えられます。

  - 索引レベルの障害
  このケースでは、索引キーが不正になっています。表データの変更に伴う索引キーの
  メンテナンスのタイミングで何らかの問題が発生した場合に索引レベルの障害が発生
  します。Oracleに起因する不具合のほとんどは索引レベルの障害です。

  - 表レベルの障害
  このケースでは、表データは特定のデータベース・ブロックのレベルで破損しており
  格納されているデータが不正になっています。

[障害箇所の特定方法]

  ORA-8102が発生した場合は、まずエラーが発生したオブジェクトが表自体かそれとも
 索引なのか、そして索引である場合はどの索引かを特定する必要があります。

 例:

  SQL> update test8102 set c1=11 where c1=1;
  update test8102 set c1=11 where c1=1
                                      *
  1行でエラーが発生しました。
  ORA-08102: 索引キーはみつかりません(オブジェクト番号 26448、dba 54525955(2))。

 エラーメッセージからオブジェクト番号が特定できますので、この番号を使用してオブ
  ジェクトの特定を行います。

  SQL> select OWNER, OBJECT_NAME, OBJECT_TYPE from DBA_OBJECTS
    2   where OBJECT_ID=26448;

  OWNER
  ------------------------------
  OBJECT_NAME
  --------------------------------------------------------------------------------
  OBJECT_TYPE
  ------------------
  U1
  IND8102
  INDEX

 この索引IND8102について情報を確認します。

  SQL> select INDEX_NAME, INDEX_TYPE, TABLE_OWNER, TABLE_NAME
    2   from user_indexes where INDEX_NAME = 'IND8102';

  INDEX_NAME                     INDEX_TYPE
  ------------------------------ ---------------------------
  TABLE_OWNER                    TABLE_NAME
  ------------------------------ ------------------------------
  IND8102                        NORMAL
  U1                             TEST8102

  索引IND8102は表TEST8102に設定されている索引ですので、この表TEST8102に対して
 ANALYZEを実行し整合性を確認します。ANALYZEの結果に応じて以下のとおり進んでくだ
 さい。ANALYZE実行に伴い対象オブジェクトに対してロックが取得されます。従って
  同時に当該オブジェクトに対する操作が行われるとANALYZEの完了まで処理が待機
  する可能性があることに注意してください。

 ケース1:ORA-01578が発生する場合

          SQL> ANALYZE TABLE TEST8102 VALIDATE STRUCTURE CASCADE;
          ANALYZE TABLE TEST8102 VALIDATE STRUCTURE CASCADE
          *
          行1でエラーが発生しました。:
          ORA-01578:
          Oracleデータ・ブロックに障害が発生しました(ファイル番号14、ブロック番号5)
          ORA-01110: データ・ファイル14:
          '/export/home/ora9202/app/oracle/oradata/ora9202/ind8102.dbf'

          ORA-01578が発生した場合は、表または索引がブロックレベルで破損している
          ことを意味します。実際に破損しているオブジェクトは以下のとおり確認する
          ことができます。

     SQL> SELECT owner, segment_name, segment_type
            2    FROM sys.dba_extents
            3   WHERE file_id = 14
            4     AND 5 between block_id AND block_id+blocks-1;

     OWNER
          ------------------------------
          SEGMENT_NAME
          --------------------------------------------------------------------
          SEGMENT_TYPE
          ------------------
          U1
          IND8102
          INDEX

          もしこの検索で返されるオブジェクトが索引である場合は、索引レベルの障害
          であることが確認できましたので、索引の再作成を実施してください。また、
          検索で返されたオブジェクトが表本体である場合は、リカバリによるデータの
          復旧または、表および索引の再作成で対処してください。
       (以下[現象発生時の対処方法]参照)

  ケース2:ORA-01499が発生する場合

          SQL> ANALYZE TABLE TEST8102 VALIDATE STRUCTURE CASCADE;
          ANALYZE TABLE TEST8102 VALIDATE STRUCTURE CASCADE
          *
          1行でエラーが発生しました。
          ORA-01499:
          表または索引の相互参照エラーです。トレース・ファイルを調べてください。

          破損箇所の切り分けのためにFULLヒントまたはNO_INDEXヒントを使用してSQL*PLUS
          などで全表走査を行います。この際に索引が設定されている列(この例では列:
          C1)に不正なデータが存在することを検索結果から確認できる場合、表の行レ
          ベルで破損をしている可能性が考えられます。また、事前に列C1がとり得る値
          を限定できる場合は、その列値を条件にして検索してみてもよいでしょう。例
          えば、列C1にはアプリケーション上11以上の値が入らないことが保証されてい
          るのであれば以下のとおり検索を行い、行が返されたら行レベルの障害である
          と判断します。この際に実行計画を採取して検索に索引を使用しているのか、
          それとも全表走査を行っているか確認を行うべきです。

          SQL> SET AUTOTORACE ON
          SQL> SELECT /*+ NO_INDEX(test8102 ind8102) */ * 
            2    FROM TEST8102 WHERE C1 >= 11;

          レコードが選択されませんでした。

          実行計画
          ----------------------------------------------------------
          0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=5 Bytes=100)
          1    0   TABLE ACCESS (FULL) OF 'TEST8102' (Cost=1 Card=5 Bytes=100)

          また、全表走査で返された行データに明らかな異常が確認できない場合は索引
          レベルで破損が生じている可能性が高いといえます。この場合は索引を再作成
          し、そのうえで再度ANALYZEを行います。

          なお、実際にORA-8102が発生した場合、表と索引のいずれのデータが不正にな
          っているのか断定できない場合があります。このような場合には、データベー
          スをバックアップからリストアし対処するのが最善の方法です。

[現象発生時の対処方法]

   索引レベルの障害:
    索引レベルの障害は索引の再作成(DROP/CREATE)により対処します。

   表レベルの障害:
     表レベルの障害は、データをアプリケーションまたは別表から復旧できるのであれ
     ば表を一旦削除し再作成することで対処可能ですが、そのようなデータの復旧が不
     可能であればバックアップからリストアし、リカバリを実施する必要があります。
     リカバリには障害が発生する前のバックアップが必須となります。ARCHIVELOGモー
   ドの環境では障害直前までデータを戻す事が可能です。NOARCHIVELOGモードの場合、
     最終的にバックアップをとった時点までの情報しか戻す事ができません。

[原因の特定方法]

  ORA-8102エラーは、上述のとおりシステムクラッシュをはじめとしてOracleを含めた
  各ソフトウェアの不具合など様々な原因で発生します。原因追究という観点では一般
  的には以下のとおり確認を進めてください。

1. OSまたはH/Wログに典型的にはDISKやI/O関連の異常が報告されている場合:
   DISK障害またはI/O関連の異常で不正なデータが書き込まれ、結果として表データと索
   引キーの不一致として顕在化した可能性が考えられます。OSまたはH/Wベンダの協力の
   もと調査を進めてください。

2. OSまたはH/Wログに特に異常が報告されていない場合:
   OSまたはH/Wログに特に異常が報告されていない場合でも、念のためOSベンダまたはH/W
   ベンダに問合せ、原因となる可能性がある報告がないか確認することを推奨します。
   OSまたはH/W関連で考えられる問題がない場合は、Oracleの製品に起因する不具合によ
   り表データと索引キーの不一致が発生している可能性について確認します。まずは以
  下の[既知の不具合]を参照し該当するものがないか確認してください。

3. 上記1.2.のいずれにも該当しない場合:
   以下の情報を踏まえてTARを登録してください。

  - OS、H/Wおよび関連ソフトウェアのログ
   - 現象発生より前24時間を含むデータベース・アラートログ
   - 現象発生時間帯を含み、24時間前程度までを目処に生成されているトレースファイル
   - ORA-8102が発生した処理(SQL文)
   - ORA-8102が発生したオブジェクトのOracleブロックダンプおよびOSレベルでのddで
     採取したHexダンプ
   - なお、ARCHIVELOGモードの場合は、状況に応じて原因追究のためにアーカイブログも
     必要になることがあります。アーカイブログは保存しておくことを推奨します。
     また、NOARCHIVELOGモードの場合は、エラー発生時のREDOログをシーケンス順にOSコ
     マンドでコピーしておいてください。但し、現象発生時のREDOログから原因を追究で
     きない場合もあります。

   『参考1:ブロック障害が検出されたオブジェクトの特定』

       SQL> SELECT * FROM dba_extents
        2 WHERE FILE_ID = file_id 
           3 AND block_id BETWEEN BLOCK_ID AND (BLOCK_ID + BLOCKS - 1);

         - file_id :エラーに表示されたファイル番号
         - block_id :エラーに表示されたブロック番号

     『参考2:Oracleブロック・ダンプ』

        2-1. V7.Xの場合
             アラートログに出力されているdba: 0x00c00b0cを10進に変換します。(=12585740)
                  systemユーザーで接続後、

              SQL> alter session set events 'immediate trace name blockdump level <DBA(10進)>';
                   user_dump_destにトレースファイルが出力されます。
               (例 ALTER SESSION SET EVENTS 'immediate trace name blockdump level 12585740';)

             2-2. V8.X以降の場合
                  V8.X以降では、相対ファイル番号/絶対ファイル番号を区別する必要
         があります。例えば、アラートログにfile=3. blocknum=2828と出力
                  されている場合、file=3は相対ファイル番号であるため、実際に絶対
                  ファイルが1つか複数かを確認します。

              SQL> select * from dba_data_files where relative_fno=3;を実行して

          [絶対ファイルが1つの場合]

              SQL> alter system dump datafile <絶対ファイル番号> block <ブロック番号>;
                 または
              SQL> alter system dump datafile '<ファイル名>' block <ブロック番号>;

                   [絶対ファイルが複数の場合]

              絶対ファイルが複数の場合は、実際に問題が生じているデータファ
                    イルがORA-01110のメッセージで表示されます。このファイルの絶
                    対ファイル番号を指定して、上記のalter system dump datafile文
              を実行します。

     『参考3:ddによるHexダンプ』

       3-1. ddコマンドによるOSのブロックダンプ
 
         Oracleのブロックはファイルの中に下記のようなイメージで配置されています。

            db_block_size 
            |<------->| 
            +---------+---------+---------+---------
            |         |         |         |
            +---+     |  Oracle | Oracle  |
            |   |     |   File  |1st Data |
            |OSD|     |  Header |  Block  |
            |         |         |         |
            |   |     | BLOCK#1 | BLOCK#2 | BLOCK#3
            +---+-----+---------+---------+--------
             <->
            512Byte

                  そのため、ddコマンドでダンプを取得するときは下記のようにコマン
                  ドを実行します。
      
            > dd bs=2k if=/home8/oradata/imt/temp/users01.dbf skip=2825 count=7 \
           | od -x > dump.txt

                  bs:    Oracle ブロックサイズ

                      -注意-
                         Oracle9iから、データベース標準ブロック・サイズ(初期化パ
                         ラメーターDB_BLOCK_SIZEで指定)とは異なるブロック・サイ
                         ズの表領域を作成することができます。このため上記bsは標
                         準のブロック・サイズとは異なる可能性があります。データ
                         ファイル名から以下のとおりブロック・サイズを確認するこ
                         とができます。

                         -データファイルと表領域の対応を確認-
                  SQL> select tablespace_name, file_name from dba_data_files
                     2 where file_name = '<ファイル名>’;

                  -表領域毎のブロック・サイズを確認-
                  SQL> select tablespace_name, block_size from dba_tablespaces;

                  if:    ファイル名
                skip:  ブロック番号
                       (例:破損ブロック番号2828を含めた前後3ブロックずつ採取す
                            るために2825を指定しています。)
               count: 取得するOracleのブロック数
                       (例:破損ブロックの前後3ブロックを含め、合計7つのデータブ
                            ロックの情報を採取します)
                    (RAWデバイスの場合はOSによって先頭にOS用の管理ブロックが
                        取られていることもあります。詳細はOSベンダまで確認してく
                        ださい。) 

          (出力例)
           0000000 0602 0000 00c0 0b0c 0003 9141 0000 0102
           0000020 0000 0000 0100 0000 0000 0d1d 0003 913f
           *
           0003760 0000 0000 2c01 0104 3131 3131 9142 0601
           0004000

     『参考4:REDOログ情報の保持の方法(NOARCHIVELOG時)』

             4-1. ARCHIVELOG/NOARCHIVELOGの確認方法

                  SQL> archive log list
                  データベース・ログ・モード     非アーカイブ・モード
                  自動アーカイブ                 使用禁止
                  アーカイブ先                    /export/home0/ora817/app/oracle/product/8.1.7/dbs/arch
                  最も古いオンライン・ログ順序   16112
                  カレント・ログ順序               16114

         現在のログ順序番号は16114であることが分かります。もしエラーが
                  検知できたのが現在のログ順序番号16114であったとしても、実際に
                  データの障害が発生したのがいつかというのはこの時点ではわかりま
                  せん。但し、NOARCHIVELOGモードの場合は16111以前のログは失われ
                  ていますので、もし障害が16111以前の場合は、REDOログから厳密な
                  調査を進めることはできません。この状態では最低限ログ順序番号
                  16112から16114までの情報を保持しておいて下さい。このログ内に原
                  因となった処理のログが含まれていれば原因の調査を行うことができ
                  る場合があります。

             4-2. オンラインREDOログの退避

      SQL> select * from v$log;

          GROUP#    THREAD#  SEQUENCE#      BYTES    MEMBERS ARC STATUS
      ---------- ---------- ---------- ---------- ---------- --- ----------------
      FIRST_CHANGE# FIRST_TI
      ------------- --------
               1          1      16114     512000          1 NO  CURRENT
         7.7146E+12 03-08-18

               2          1      16112     512000          1 NO  INACTIVE
         7.7146E+12 03-08-17

               3          1      16113     512000          1 NO  INACTIVE
         7.7146E+12 03-08-17

      SQL> select * from v$logfile;

         GROUP# STATUS
      ---------- -------
      MEMBER
      --------------------------------------------------------------------------------
               1
      /export/home0/ora817/app/oracle/oradata/ora817/redo03.log

               2
      /export/home0/ora817/app/oracle/oradata/ora817/redo02.log

               3
      /export/home0/ora817/app/oracle/oradata/ora817/redo01.log

      上記を前提とすれば、以下のとおりOSコマンドでログを退避しておいてください。

      % cp /export/home0/ora817/app/oracle/oradata/ora817/redo02.log /xxxx/seq16112.log
      % cp /export/home0/ora817/app/oracle/oradata/ora817/redo03.log /xxxx/seq16113.log

      またログスイッチ後、ログ順序番号16114のログも以下のとおり退避します。

      % cp /export/home0/ora817/app/oracle/oradata/ora817/redo01.log /xxxx/seq16114.log