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

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

[エラー・メッセージ]

ORA-01578 Oracle データ・ブロックに障害が発生しました(ファイル番号: string、ブロック番号: string)

原因:指定されたデータ・ブロックに障害が発生しました。プログラム・エラーの可能性
があります。
処置:次のようなコマンドを使用して、どのオブジェクトに障害があるか調べてください。

SELECT SEGMENT_TYPE,OWNER||'.'||SEGMENT_NAME FROM DBA_EXTENTS
WHERE file = FILE_ID AND block BETWEEN BLOCK_ID AND BLOCK_ID+BLOCKS -1;

file およびblock の値は、メッセージに表示されたものを使用してください。

指定されたブロックを含むセグメントのリストアを試行してください。このために
は、セグメントを削除し、再作成する必要があります。トレース・ファイルがある
場合、そこに記録されているエラーをオラクル社カスタマ・サポート・センターに
連絡してください。

[技術的説明]

- エラー内容説明

Oracle はデータブロックを参照する際に、ブロックの妥当性をチェックします。
デフォルトではブロックヘッダおよびブロックの末尾 4 byte のデータをチェックし、
異常を検知すると ORA-1578 を出力します。
また、このチェック機能は、後述する初期化パラメータの設定によりさらに強化されます。

[エラー発生例]

- アプリケーション
SQL> select * from test
*
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 3, block # 2828)
ORA-01110: data file 2: '/home8/oradata/imt/temp/users01.dbf'

- alert ファイル
***
Corrupt block relative dba: 0x00c00b0c file=3. blocknum=2828.
Fractured block found during buffer read
Data in bad block - type:6. format:2. rdba:0x00c00b0c
last change scn:0x0000.00039141 seq:0x1 flg:0x02
consistancy value in tail 0x91420601
check value in block header: 0x0, check value not calculated
spare1:0x0, spare2:0x0, spare2:0x0
***
Reread of rdba: 0x00c00b0c (file 3, block 2828) found same corrupted data

[対処方法]

1. 破損状況の確認

まずディスク上でブロックが実際に破損しているのか、ディスクからバッファへの読
み込み時の問題で、バッファ上のみで破損しているのか確認する必要があります。
(ORA-1578 発生時には、上記 alert ファイルにも出力されているように、再度同じブ
ロックをディスクから読み込むことを試みます。そのため、バッファ上のみで破損し
ている可能性は非常に低いものとなります。)

1-1. 破損ブロックの特定
ORA-1578 発生時の alert.log ファイルの以下の出力から、ファイル番号および
ブロック番号を確認します。

Corrupt block relative dba: 0x00c00b0c file=3. blocknum=2828.

file= XX : 相対ファイル番号
blocknum= YY : ブロック番号

相対ファイル番号を使用して、以下のSQL 文を実行して絶対ファイル
番号を確認します。

SELECT FILE_ID FROM DBA_DATA_FILES WHERE RELATIVE_FNO=XXX;

実行例)
SQL> SELECT FILE_ID FROM DBA_DATA_FILES WHERE RELATIVE_FNO=3;

FILE_ID
----------
2

この絶対ファイル番号とブロック番号を使用して、以下の SQL 文を実行
します。

SELECT SEGMENT_TYPE,OWNER||'.'||SEGMENT_NAME FROM DBA_EXTENTS
WHERE XXX = FILE_ID AND YYY BETWEEN BLOCK_ID AND BLOCK_ID+BLOCKS -1;

実行例)
SQL> SELECT SEGMENT_TYPE,OWNER||'.'||SEGMENT_NAME FROM DBA_EXTENTS
2  WHERE 2 = FILE_ID AND 2828 BETWEEN BLOCK_ID AND BLOCK_ID+BLOCKS -1;

SEGMENT_TYPE       OWNER||'.'||SEGMENT_NAME
------------------ ------------------------
TABLE              SCOTT.TEST

* この表が、ディクショナリ等ではなく、ユーザ表であることを確認してください。
* Document 1717817.1(KROWN:51288) v$datafile では表示されないファイル番号がメッセージに出力される
もご参照ください。
     alert.logからではなく、ORA-1578のエラーメッセージからファイル番号とブロック
     番号を取得する場合のファイル番号が表すファイルの例外に気をつけてください。

1-2. データベースの停止
データの復旧よりも原因究明を優先させる場合は、下記[取得情報]を確認して
     情報の取得を行ってください。その後でデータベースを停止してください。

1-3. DB_VERIFY の実行(Document 1708650.1(KROWN:26754) 参照)
--> この時点でエラーが発生すれば、ディスク上でも破損していますので、
2.のデータの復旧をお願いします。

1-4. データベースの起動

1-5. analyze の実行
以下の SQL 文を実行します。
SQL> analyze table XXX validate structure cascade;
--> この時点でエラーが発生しなければ、バッファ上のみで破損していたと考
えられるため、対処の必要はありません。
※パーティション表の場合、Document 1703145.1(KROWN:13655) に従い、utlvalid.sql の実行
が必要になります。

2. データの復旧
  ORA-1578が発生すると、そのブロックを含む表の全件検索が失敗するなど、
  オブジェクトに対する処理に支障を来たします。ブロックを復旧させるか、
  そのブロックに含まれたデータを破棄して処理を継続するかを検討する必要が
  あります。以下にそれぞれについて検討できる選択肢を挙げます。
  2-1. 破損したブロックを完全に元に戻す
・オブジェクトの再作成
・EXPORTしてあったデータのIMPORT
・テキストで保存してあったデータをSQL*Loaderでロード
・リカバリ
2-2. 破損したブロックを読み飛ばす
     通常は上記方法による復旧を行うことが望ましいですが、破損した
     ブロックに含まれているデータをスキップして表からデータを抽出
     する必要がある場合などに以下の方法を取ることが出来ます。
・DBMS_REPAIR パッケージを使用する (Document 1717045.1(KROWN:48684) 参照)
(Oracle 8.1.5 以降のバージョンで使用可能です)

3. データベース全体の確認
必要に応じて、データベースのファイルすべてに DB_VERIFY を実行し、他のブロック
に破損が無いか確認することを推奨します。

[取得情報]

1. 破損している箇所を確認するため、まずは下記の3つの情報が必要になります。

1-1. アプリケーションに返されたメッセージ
1-2. alert.log ※
1-3. 以下の SQL 文の実行結果
SQL> SELECT SEGMENT_TYPE,OWNER||'.'||SEGMENT_NAME FROM DBA_EXTENTS
2  WHERE file = FILE_ID AND block BETWEEN BLOCK_ID AND BLOCK_ID+BLOCKS -1;

※ 本エラーは、11g 以降では、ADR によってクリティカル・エラーとして追跡
され、インシデント番号が振られます。Document 1746336.1(KROWN:135295) の方法を利用して、
該当のインシデント番号の初期調査に必要な診断情報を1つの zip ファイル
に自動でまとめることが可能です。
11g でインシデントファイルが生成されるエラー(Document 1740801.1(KROWN:126440))のSRを登録
する際は、Document 1746336.1(KROWN:135295) の方法でまとめた zip ファイルをアップロード
してください。

2. 次に壊れたブロックのダンプ情報を取得します。

2-1. dd/odコマンドによるOSのブロックダンプ

※ dd/od コマンドがないプラットフォームの場合は、UNIX マシンにデータファイ
    ルをコピー後、実行していただくことも可能です

Oracleのブロックはファイルの中に下記のようなイメージで配置されています。

db_block_size
|<------->|
+---------+---------+---------+---------+---
|         |         |         |         |
+---+     |  Oracle | Oracle  | Oracle  |
|   |     |   File  |1st Data |2nd Data |
|OSD|     |  Header |  Block  |  Block  |
|         |         |         |         |
|   |     | BLOCK#1 | BLOCK#2 | BLOCK#3 |
+---+-----+---------+---------+---------+---
<->
512Byte (OSD = ポート固有の情報を格納するブロック)

そのため、ddコマンドでダンプを取得するときは下記のようにコマンドを実行します。
> dd bs=2k if=/home8/oradata/imt/temp/users01.dbf skip=2823 count=11 \
| od -x > dump.txt
※ 前後 5ブロック含め(計11ブロック)取得をお願いします。

bs:    Oracle ブロックサイズ
if:    ファイル名
skip:  ブロック番号
count: 取得するOracleのブロック数
(ローデバイスの場合はOSによって先頭にOS用の管理ブロックが
取られていることもありますので、ベンダー様にご確認ください)
※ dd コマンドはプラットフォームによって異なります。

- Solaris, HP-UX, AIX の場合
% dd bs=2k if=/home8/oradata/imt/temp/users01.dbf skip=2823 count=11 \
| od -xv > dump.txt

- Linux の場合
% dd bs=2k if=/home8/oradata/imt/temp/users01.dbf skip=2823 count=11 \
| od -txC -v > dump.txt

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

1 行目の"00c0 0b0c"は相対DBAを示します。この部分の値がalertの"dba: 0x00c00b0c"と
同じであることを確認後、弊社サポートセンターまでご送付ください。

※ WindowsNT/2000,Linux等のIntel CPUのプラットフォームは、リトルエンディアン
   のため、上記の dd の出力結果の DBA "00c0 0b0c" の表示が "0b0c 00c0" と
     逆転されます。

2-2. Oracleのブロックダンプ

2-2-1. V7.Xの場合
dba: 0x00c00b0cを10進に変換します。(=12585740)
systemユーザーで接続後、
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-2. V8.Xの場合
V8.X以降では、相対ファイル番号/絶対ファイル番号を区別する必要があり
ます。例えば、alertにfile=3. blocknum=2828と出力されている場合、
file=3は相対ファイル番号であるため、実際に
select * from dba_data_files where relative_fno=3;を実行して
相対ファイルが1つか複数かを確認します。

(相対ファイルが1つの場合)
ORA-1578と同時に出力されているORA-01110のメッセージのファイル番号が
絶対ファイル番号です。このファイル番号を指定して、以下のalter system
dump datafile文を実行します。
alter system dump datafile <絶対ファイル番号> block min <ブロック番号-5> block max <ブロック番号+5>;

または
alter system dump datafile '<ファイル名>'  block min <ブロック番号-5> block max <ブロック番号+5>;

を実行後、user_dump_destのトレースファイルを送付してください。

(相対ファイルが複数の場合)
問題のオブジェクトが存在している表領域を確認してください。
dba_data_filesに複数存在する相対ファイルのうち、確認した表領域に属
しているのが今回問題となっているファイルです。絶対ファイル番号を確
認し、上記 alter system dump datafile文コマンドを実行してください。

3. 上記の結果で異常が見られない場合はメモリ上で壊れている可能性があります。
その場合、メモリダンプの情報をお願いすることがございます。(8.0 以降のバージョ
ンのみ可能)

systemユーザーで接続後、
3-1. select ts# from v$datafile
where name='ファイル名';
(例 select ts# from v$datafile
where name='/home8/oradata/imt/temp/users01.dbf';

3-2. alter session set events 'immediate trace name set_tsn_p1 level <TS#+1>';
<TS#+1>には1.で検索したTS#に1を足した値を入力します。
(例 alter session set events 'immediate trace name set_tsn_p1 level 3';)

3-3. alter session set events 'immediate trace name BUFFER level <DBA(10進)>;
(例 alter session set events 'immediate trace name BUFFER level 12585740';)

3-4. user_dump_destには下記の行を含むトレースが出力されます。
BH #178 (0x800d9ed8) file#: 3 rdba: 0x00c00b0c (3/2828) class 1 ba: 0x8125d000
(このトレースファイルを送付してください。すでにブロックがバッファに
存在しない場合は、この情報は出力されません。)

3-5. 3-4.の"ba:XXXXXXXX" (例では0x8125d000)がバッファのアドレスを指します。

3-6. sqlplus で、as sysdba として接続します。
    (8.1 以下のバージョンでは svrmgrl で internal として接続します)

3-7. oradebug setmypid

3-8. oradebug peek <バッファアドレス> <ブロックサイズ(16進)> 1
実行例) SQL> connect / as sysdba
接続されました。
SQL> oradebug setmypid
文が処理されました。
SQL> oradebug peek 0x8125d000 0x800 1
[8125D000, 8125D800) = 06020000 00C00B0C 00000000 0000FF00 00000000 ...
"00C00B0C"は相対DBAを示します。この値がalertの"dba: 0x00c00b0c"と同じで
あることを確認後、user_dump_destに出力されたトレースを送付してください。
トレースファイル出力例)
*** 2000.11.01.17.59.20.000
[8125D000, 8125D800) = 06020000 00C00B0C 00000000 0000FF00 00000000 ...
Dump of memory from 0x8125D014 to 0x8125D800
8125D000                                              01000000 00000D1D 0003913F
8125D020 00000000 00010300 00000000 00020011 00000099 01001490 008306FC 20010000
8125D040 00039141 00010001 FFFF0014 07B0079B 079B0000 000107B0 00060000 07780000

4. OS のメッセージファイル
messages, syslog 等の OS が出力するメッセージファイルを送付してください。

5. その他
状況に応じて原因追究のためにアーカイブログも必要になることがあります。アーカ
イブログは保存しておくことを推奨します。

[破損事例]

破損状況は概ね以下の3つに分かれます。
(各事例は、OS エラーを伴わず ORA-1578 が発生したケースを紹介しています。)

1. Oracle による破損ではない事例
1-1. Oracle のブロックサイズではない値のサイズ分の領域のデータが異常な場合
事例)  ディスク上のブロックには問題はないが、SELECT を実行すると
ORA-1578 が発生。

[破損状況]
メモリのダンプ情報より、ブロックの最後の 512 byte が
ffff ffff aaaa aaaa 5555 5555 0000 0000 の繰り返しとなり、
異常な値であった。

Oracle Block
+---------+
|         |
|         |
|         |
|         |
|ffff aaaa|
|5555 0000|  最後の 512byte
+---------+  のみ破損

(原因)
同じように問題のないデータファイルを cp コマンドで別ファイルに
コピーすると、コピー先のファイル内のブロックも、上記と同じ破損
状況であったため、OS あるいは ハードの問題と断定。

1-2. 複数のブロックが破損しており、それぞれ、ブロック内の物理的に同一位置
かつ論理的に異なる位置が破損している場合

事例) データベースOracle のバックアップをリストアして、運用を行うと
複数のブロックに対して、ORA-1578 が発生した。

[破損状況]
破損したすべてのブロックの先頭から 1187 byte 目のデータの、
1 bit が異常な値となっていたが、Oracle の管理データとしては、
行ヘッダ部分であったり、列ヘッダ部分であったりと論理的に異なる
箇所に異常がみられた。

Oracle Block A       Oracle Block B
+---------+          +---------+
|         |          |         |
|         |          |         |
|         |          |         |
|      X  |          |      X  |
|         |          |         |
|         |          |         |
+---------+          +---------+
行ヘッダ破損         列ヘッダ破損

すべてのブロックは、先頭から 1187byte 目が破損

[原因]
バックアップする際のテープデバイスに問題があることが確認できた。

2. Oracle による破損である可能性が高い事例
2-1. 複数のブロックの物理的に異なる位置でデータが破壊されており、その破損
個所が論理的に同一である場合
例) 物理的に異なる箇所が破損し、かつ、破損個所がすべて行ヘッダである等

3. Oracle の問題か否かが不明な事例
3-1. 複数のブロックが破損しており、それぞれ、ブロック内の物理的に同一位置
かつ論理的にも同一の位置が破損している場合

事例) ブロック破損のため、業務アプリケーションが停止した。

[破損状況]
破損したすべてのブロックの先頭から 2 byte 目のデータが、異常な
値となっていた。

Oracle Block A       Oracle Block B
+---------+          +---------+
| X       |          | X       |
|         |          |         |
|         |          |         |
|         |          |         |
|         |          |         |
|         |          |         |
+---------+          +---------+
管理情報破損         管理情報破損

すべてのブロックは、先頭から 2 byte 目が破損

[原因]
1-2. の事例と類似していますが、先頭から 2 byte 目は、ブロック
のヘッダ情報の一部で、特定の情報が書き込まれます。
2 byte 目ということで物理的な破損個所が同じですが、論理的
(Oracle が使用する特定の情報)な位置も同じであるため、Oracle
の問題かどうかの判断ができませんでした。
(最終的にはハードの入れ替えにより、現象は再現しなくなりました。)

[チェック機能を強化する初期化パラメータ]
- db_block_checksum
このパラメータを true に設定すると、DBWn およびダイレクト・ローダーが、
チェックサム(ブロック内に格納されているすべてのバイトから計算された数値)
を計算し、ディスクにデータ・ブロックを書き込むときに、すべてのデータ・ブ
ロックのブロック・ヘッダににそのチェックサム値を格納します。次回、そのブ
ロックが読み込まれると、チェックサムが検証されます。
また、このパラメータを false にしている場合でも、SYSTEM 表領域
に対しては、チェックサムを計算します。
このパラメータによるオーバーヘッドは通常、1~2% のため、true に設定する
ことを推奨します。
- db_block_checking (V8.1 以降)
このパラメータを true に設定すると、ブロックの更新が行われた時にブロックの
整合性チェックを行います。
8.0までのバージョンではイベントによって実現されていました。

8.0までの対応イベント(init.oraでのみ設定可能) :
イベント10210: データ・ブロックで更新が発生したら整合性チェックを行う
イベント10211: 索引ブロックで更新が発生したら整合性チェックを行う
イベント10212: クラスタ・ブロックで更新が発生したら整合性チェックを行う

設定例)
event="10210 trace name context forever, level 10"
event="10211 trace name context forever, level 10"
event="10212 trace name context forever, level 10"

8.1.6以降のバージョンでは、このパラメータの設定にかかわらずSYSTEM表領域の
ブロックは必ずチェックが行われます。
この設定により、ブロックが更新されるたびにチェックを行うようになるので、
更新によってブロックが破損するとただちにエラーが発生するようになりますが、
チェックのためのオーバヘッドが発生しパフォーマンスに影響を与えます。
(1~10%程度 : 但しCPUやメモリ等のH/W環境、処理内容に依存するため、場合に
よっては 20% のオーバヘッドが発生することもあります。事前にテスト環境にて
オーバーヘッドを確認してください。)