ぱと隊長日誌

ブログ運用もエンジニアとしての生き方も模索中

Oracle Database のデータ・ブロックのダンプとその解析

目的

Oracle Databaseのデータ・ブロックをダンプするコマンドは正式にドキュメント化されていない。ただ、断片的な情報がいくつかのエントリで公開されている。このエントリでダンプ方法とその実例、及び解析の概要とさらに詳細を知るためのエントリへのリンクをまとめる。

基礎知識

Oracleの論理記憶構造について理解しておく必要がある。
以下にOracle Databaseリファレンス12cR1の論理記憶構造のページのリンクを提示する。
論理記憶域構造

データ・ブロックのダンプ

コマンド

特定行が格納されたデータ・ブロックを調べる
SELECT
    DBMS_ROWID.ROWID_TO_ABSOLUTE_FNO(ROWID, 'schema_name', 'table_name') FILE_ID,
    DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BLOCK_ID
  FROM table_name
  WHERE condition

schema_name:表が含まれるスキーマの名前。
table_name:表名。
condition:調べたい行を特定する。
FILE_ID:ROWIDの絶対ファイル番号を戻す。
BLOCK_ID:ROWIDのブロック番号を戻す。

DBMS_ROWID
Oracle Databaseリファレンス 12cR1のDBMS_ROWIDパッケージの説明。

セグメント名でデータ・ブロックの範囲を調べる
SELECT FILE_ID, BLOCK_ID, BLOCKS
FROM   DBA_EXTENTS
WHERE  SEGMENT_NAME = 'segment_name';

segment_name:調べたいセグメント名を指定する。セグメントは表でも索引でも可。
FILE_ID:エクステントが設定されているファイルのファイル番号。
BLOCK_ID:エクステントの先頭ブロック番号。
BLOCKS:Oracleブロック単位のエクステントのサイズ。

セグメントのブロックの範囲は(BLOCK_ID)~(BLOCK_ID + BLOCKS - 1)となる。

なお、セグメントは複数のエクステントで構成されることがあり、エクステント間のデータ・ブロックが連続しているとは限らない(エクステント内のデータ・ブロックは連続している)。手作業で複数のデータ・ブロックのダンプを個々に行うのは手間だが、SPOOLでダンプのSQLを出力しているエントリを参考に挙げる。
ロックに関する検証 その7 | Insight Technology, Inc.

DBA_EXTENTS
Oracle Databaseリファレンス 12cR1のDBA_EXTENTSの説明。

単一のデータ・ブロックをダンプする
ALTER SYSTEM DUMP { DATAFILE | TEMPFILE } { file_id | 'file_name' }
BLOCK block_id;

file_id:ファイル番号
block_id:ブロック番号

複数のデータ・ブロックをダンプする
ALTER SYSTEM DUMP { DATAFILE | TEMPFILE } { file_id | 'file_name' }
BLOCK MIN block_id_min BLOCK MAX block_id_max;

file_id:ファイル番号
block_id_min:開始ブロック番号
block_id_max:終了ブロック番号

「セグメント名でデータ・ブロックの範囲を調べる」で説明したSQLを使ってブロック範囲を調べた場合、
file_id:FILE_ID
block_id_min:BLOCK_ID
block_id_max:BLOCK_ID + BLOCKS - 1
となる。

ダンプファイルの出力先

11g以降(12cR1でも確認) : <DIAGNOSTIC_DEST>/diag/rdbms/<DB_NAME>/<SID>/trace
10g以前 : <USER_DUMP_DEST>

ダンプが書き込まれるトレースファイル名

トレース・ファイル名の形式は次のようになる。
sid_ora_pid_traceid.trc
この例で、sidはOracleインスタンスID、pidはプロセスID、traceidはTRACEFILE_IDENTIFIERパラメータの値を示す。

TRACEFILE_IDENTIFIERパラメータは次のように設定できる。

ALTER SESSION SET TRACEFILE_IDENTIFIER = 'traceid';

TRACEFILE_IDENTIFIER
Oracle Databaseリファレンス 12cR1のTRACEFILE_IDENTIFIERパラメータの説明。

検証

環境

Hyper-V上の仮想マシン(メモリ:2048MB)
Oracle Linux Server release 6.7
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production

検証用に作成したTRYユーザ(TRYスキーマ)で検証を行う。

実行例

テーブルとデータを投入し、ダンプを実行する。

SQL> CREATE TABLE
         TRY_DUMP_TBL (ID NUMBER, COL0 VARCHAR2(5), COL1 VARCHAR2(5));

表が作成されました。

SQL> INSERT INTO
         TRY_DUMP_TBL (ID, COL0, COL1)
         VALUES (1, 'AAAAA', 'ZZZZZ');

1行が作成されました。

SQL> INSERT INTO
         TRY_DUMP_TBL (ID, COL0, COL1)
         VALUES (2, 'BBBBB', 'ZZZZZ');

1行が作成されました。

SQL> INSERT
         INTO TRY_DUMP_TBL (ID, COL0, COL1)
         VALUES (3, 'CCCCC', 'ZZZZZ');

1行が作成されました。

SQL> COMMIT;

コミットが完了しました。

SQL> ALTER SYSTEM CHECKPOINT;

システムが変更されました。

SQL> SELECT
         DBMS_ROWID.ROWID_TO_ABSOLUTE_FNO(ROWID, 'TRY', 'TRY_DUMP_TBL') FILE_ID,
         DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BLOCK_ID
     FROM TRY_DUMP_TBL;

   FILE_ID   BLOCK_ID
---------- ----------
         6        347
         6        347
         6        347

SQL> ALTER SESSION SET TRACEFILE_IDENTIFIER = 'dumpdatafile';

セッションが変更されました。

SQL> ALTER SYSTEM DUMP DATAFILE 6 BLOCK 347;

システムが変更されました。

データ・ダンプ・ファイルの出力場所を確認する。

SQL> show parameter diagnostic_dest

NAME             TYPE    VALUE
---------------- ------- ----------------
diagnostic_dest  string  /u01/app/oracle

SQL> show parameter db_name;

NAME             TYPE    VALUE
---------------- ------- ----------------
db_name          string  odb

$ echo $ORACLE_SID
odb

今回の場合、以下にデータ・ダンプ・ファイルが作成される。
/u01/app/oracle/diag/rdbms/odb/odb/trace/odb_ora_2991_dumpdatafile.trc

データ・ダンプ・ファイル

以下の解説はこのデータを用いて行う。

Trace file /u01/app/oracle/diag/rdbms/odb/odb/trace/odb_ora_2991_dumpdatafile.trc
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
ORACLE_HOME = /u01/app/oracle/product/12.1.0/dbhome_1
System name:	Linux
Node name:	node1.oracle12c.jp
Release:	3.8.13-98.1.2.el6uek.x86_64
Version:	#2 SMP Thu Aug 13 12:24:05 PDT 2015
Machine:	x86_64
Instance name: odb
Redo thread mounted by this instance: 1
Oracle process number: 75
Unix process pid: 2991, image: oracle@node1.oracle12c.jp (TNS V1-V3)


*** 2015-08-17 07:18:51.792
*** SESSION ID:(365.14697) 2015-08-17 07:18:51.792
*** CLIENT ID:() 2015-08-17 07:18:51.792
*** SERVICE NAME:(SYS$USERS) 2015-08-17 07:18:51.792
*** MODULE NAME:(SQL*Plus) 2015-08-17 07:18:51.792
*** CLIENT DRIVER:(SQL*PLUS) 2015-08-17 07:18:51.792
*** ACTION NAME:() 2015-08-17 07:18:51.792
 
Start dump data blocks tsn: 4 file#:6 minblk 347 maxblk 347
Block dump from cache:
Dump of buffer cache at level 4 for pdb=0 tsn=4 rdba=25166171
BH (0x79bed498) file#: 6 rdba: 0x0180015b (6/347) class: 1 ba: 0x79a56000
  set: 10 pool: 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 0,0
  dbwrid: 0 obj: 92108 objn: 92108 tsn: [0/4] afn: 6 hint: f
  hash: [0x8cf760b8,0x813f22d0] lru: [0x79bed6c0,0x79bed440]
  ckptq: [NULL] fileq: [NULL]
  objq: [0x70ec4958,0x79bed468] objaq: [0x70ec4948,0x79bed478]
  st: XCURRENT md: NULL fpin: 'ktspbwh2: ktspfmdb' fscn: 0x0.205915 tch: 4
  flags: block_written_once
  LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [1]
Block dump from disk:
buffer tsn: 4 rdba: 0x0180015b (6/347)
scn: 0x0.205923 seq: 0x01 flg: 0x06 tail: 0x59230601
frmt: 0x02 chkval: 0xb454 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x00007F384E735000 to 0x00007F384E737000
7F384E735000 0000A206 0180015B 00205923 06010000  [....[...#Y .....]
7F384E735010 0000B454 00000001 000167CC 00205915  [T........g...Y .]
7F384E735020 00000000 00320002 01800158 00170009  [......2.X.......]
7F384E735030 00000640 0100B54F 00060154 00002003  [@...O...T.... ..]
7F384E735040 00205923 00000000 00000000 00000000  [#Y .............]
7F384E735050 00000000 00000000 00000000 00000000  [................]
7F384E735060 00000000 00030100 0018FFFF 1F4A1F62  [............b.J.]
7F384E735070 00001F4A 1F860003 1F621F74 00000000  [J.......t.b.....]
7F384E735080 00000000 00000000 00000000 00000000  [................]
        Repeat 499 times
7F384E736FC0 00000000 012C0000 04C10203 43434305  [......,......CCC]
7F384E736FD0 5A054343 5A5A5A5A 0203012C 420503C1  [CC.ZZZZZ,......B]
7F384E736FE0 42424242 5A5A5A05 012C5A5A 02C10203  [BBBB.ZZZZZ,.....]
7F384E736FF0 41414105 5A054141 5A5A5A5A 59230601  [.AAAAA.ZZZZZ..#Y]
Block header dump:  0x0180015b
 Object id on Block? Y
 seg/obj: 0x167cc  csc: 0x00.205915  itc: 2  flg: E  typ: 1 - DATA
     brn: 0  bdba: 0x1800158 ver: 0x01 opc: 0
     inc: 0  exflg: 0
 
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0009.017.00000640  0x0100b54f.0154.06  --U-    3  fsc 0x0000.00205923
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
bdba: 0x0180015b
data_block_dump,data header at 0x7f384e735064
===============
tsiz: 0x1f98
hsiz: 0x18
pbl: 0x7f384e735064
     76543210
flag=--------
ntab=1
nrow=3
frre=-1
fsbo=0x18
fseo=0x1f62
avsp=0x1f4a
tosp=0x1f4a
0xe:pti[0]	nrow=3	offs=0
0x12:pri[0]	offs=0x1f86
0x14:pri[1]	offs=0x1f74
0x16:pri[2]	offs=0x1f62
block_row_dump:
tab 0, row 0, @0x1f86
tl: 18 fb: --H-FL-- lb: 0x1  cc: 3
col  0: [ 2]  c1 02
col  1: [ 5]  41 41 41 41 41
col  2: [ 5]  5a 5a 5a 5a 5a
tab 0, row 1, @0x1f74
tl: 18 fb: --H-FL-- lb: 0x1  cc: 3
col  0: [ 2]  c1 03
col  1: [ 5]  42 42 42 42 42
col  2: [ 5]  5a 5a 5a 5a 5a
tab 0, row 2, @0x1f62
tl: 18 fb: --H-FL-- lb: 0x1  cc: 3
col  0: [ 2]  c1 04
col  1: [ 5]  43 43 43 43 43
col  2: [ 5]  5a 5a 5a 5a 5a
end_of_block_dump
End dump data blocks tsn: 4 file#: 6 minblk 347 maxblk 347

ツール

Oracle 7~Oracle 10gまではBBED utility (block browser and editor)というOracle技術サポート用ツールが同梱されていた。このツールではデータ・ブロックを確認するだけでなく、編集も可能となっていた。Oracle 11gで外されたが、自力でmakeすることができるらしい。利用する場合は自己責任で行うこと。ツールの説明やマニュアルへのリンクは以下を参照のこと。
Oracle BBED tips

参考

How to dump Oracle Data Block? | Oracle Database: Lets explore it Blog
OracleのブログにOracle Databaseのデータ・ブロックをダンプするコマンドを記載している。Oracleが公開している数少ない資料。

Formatted Data Block Dumps
Oracleのブログよりもコマンドや出力先の詳細までまとめられている。

データ・ブロックの解析

テーブルのレコードのデータ・ブロック

「データ・ダンプ・ファイル」の例を用い、以下のエントリを参考に解説する。
行移行・行連鎖に関する検証 その2 | Insight Technology, Inc.
Kamran Agayev's Oracle Blog » Blog Archive » Dumping an Oracle data block, reading the output and doing some math
Index Block Dump: Block Header Part I (Editions Of You) | Richard Foote's Oracle Blog

Start dump data blocks tsn: 4 file#:6 minblk 347 maxblk 347

file#はダンプしたファイル番号。
minblk/maxblkはダンプしたブロック番号。

rdba: 0x0180015b (6/347)

rdbaの"0x0180015b"は32bitsでデータ・ブロックのアドレスを示しており、最初の10bitsがファイル番号、残りの22bitsがブロック番号となる。"(6/347)"は(ファイル番号/ブロック番号)を表している。

16進数の"0x0180015b"は10進数で"25166171"となる。これを以下のファンクションにパラメータとして渡すことで、ファイル番号及びブロック番号に変換できる。

SQL> SELECT
         DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(25166171) FILE_ID
     FROM DUAL;

   FILE_ID
----------
         6

SQL> SELECT
         DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(25166171) BLOCK_ID
     FROM DUAL;

  BLOCK_ID
----------
       347

ファイル番号とブロック番号からデータ・ブロック・アドレスを計算するファンクションもある。

SQL> SELECT
         DBMS_UTILITY.MAKE_DATA_BLOCK_ADDRESS(6, 347) ADDRESS
     FROM DUAL;

   ADDRESS
----------
  25166171

DBMS_UTILITY
Oracle Databaseリファレンス 12cR1のDBMS_UTILITYパッケージの説明。

scn: 0x0.205923

scnはデータ・ブロックが最後に更新された時のシステム変更番号(SCN)。

seq: 0x01

seqは同じSCNで複数回更新された場合の識別に用いられる。
insertで0x01。同一トランザクションのupdate1回で0x02、update2回で0x03となる。

詳細は以下のエントリを参照のこと。
Block Sequence Number & SCN | Amit Saraswat

tail: 0x59230601

tailの値は以下で構成されている。
(SCNの最後2バイト)+(typeの値)+(seqの値)

frmt: 0x02

frmtはブロックのフォーマット。
0x01はOracle 7、0x02はOracle 8以降(Oracle 12cR1でも確認)。

ntab=1

ntabはブロックに格納されている表数。

nrow=3

nrowはブロックに格納されている行数。

0xe:pti[0]	nrow=3	offs=0
0x12:pri[0]	offs=0x1f86
0x14:pri[1]	offs=0x1f74
0x16:pri[2]	offs=0x1f62

offsは行情報(ブロック内の行位置)。
pri[0]は1行目、pri[1]は2行目、以下その繰り返し。

block_row_dump:
tab 0, row 0, @0x1f86
tl: 18 fb: --H-FL-- lb: 0x1  cc: 3
col  0: [ 2]  c1 02
col  1: [ 5]  41 41 41 41 41
col  2: [ 5]  5a 5a 5a 5a 5a
tab 0, row 1, @0x1f74
tl: 18 fb: --H-FL-- lb: 0x1  cc: 3
col  0: [ 2]  c1 03
col  1: [ 5]  42 42 42 42 42
col  2: [ 5]  5a 5a 5a 5a 5a
tab 0, row 2, @0x1f62
tl: 18 fb: --H-FL-- lb: 0x1  cc: 3
col  0: [ 2]  c1 04
col  1: [ 5]  43 43 43 43 43
col  2: [ 5]  5a 5a 5a 5a 5a
end_of_block_dump

block_row_dump~end_of_block_dumpまでが論理ダンプ。

"@0x1f86"はoffsと対応している。他、@で始まる16進の数字は同様。
"tl: 18"は行断片の長さ。
"fb: --H-FL--"は行の状態。Hはヘッダ、Fは行の先頭、Lは行の終わり。
"cc: 3"は列数。
"col 0"はテーブルの1列目、"col 1"はテーブルの2列目、以下その繰り返し。

データ・ブロックの詳細な解説リンク集

行移行・行連鎖に関する検証 その3 | Insight Technology, Inc.
行移行時のデータ・ブロックについて解説している。

ロックに関する検証 その7 | Insight Technology, Inc.
ビットマップ・インデックスのデータ・ブロックについて解説している。

おら! オラ! Oracle再検証 @IT出張所(1):パフォーマンス劣化はインデックスのせいなのか!? をみっちり検証 (4/4) - @IT
インデックスのリーフブロックのデータ・ブロックについて解説している。

Oracle Database 12cR1 で列追加した時の行データブロック検証 - ぱと隊長日誌
列追加時のデータ・ブロックについて解説している。

更新情報

2015/08/23

列追加時のデータ・ブロック解説エントリへのリンクを追加した。