ログマイナーに関する検証 その3

< ログマイナに関する検証 その参 > ペンネーム チョビひげ

— ログ・マイナーで連鎖行を見る —

ログ・マイナーでドロップしてしまったテーブルを復旧する前に注意しなけれ
ばいけないことは以下の操作対象をログ・マイナーがサポートしていないこと
である。(Oracle8i)

・連鎖行
・索引構成表
・クラスタ化表/索引
・非スカラー型
・ダイレクト・パス・インサート
・DDL文

では、ログ・マイナーを実行したときに連鎖行はどのように表示されるのか検
証してみよう。

行連鎖は行を挿入する際に、その行のデータが大きすぎて一つのブロック内に
収まらない場合に発生する。では実際に行連鎖を発生させ、どのようにログ・
マイナーで見られるのであろうか。

1.テーブル(DOCUMENT)に以下の1件のレコード(DOCUMENT_DATAに2458Byte)を挿入

SQL> desc document;

Name                                    Null?    Type
--------------------------------------- -------- ---------------------
DOCUMENT_ID                                      NUMBER
DOCUMENT_DATA                                    VARCHAR2(4000)


SQL> insert into document values(1,'[n*2458]');
                               ※[n*2458]はnが2458文字をあらわしてる

以下の手順で実際に行連鎖されているか確認してみよう。

# CHAINED_ROWS表を作成する為、UTLCHAIN.SQLを実行する

SQL> @utlchain.sql

Table created.

# ANALYZEコマンドをLIST CHAINED ROWSオプションで実行

SQL> analyze table document list chained rows;

Table analyzed.

# 上記のコマンドでCHAINE_ROWS表にデータが格納される
# 格納された行連鎖を検索

SQL> select table_name, head_rowid from chained_rows;

TABLE_NAME                     HEAD_ROWID
------------------------------ ------------------
DOCUMENT                       AAAGW4AAFAAAR+JAAA

AAAGW4AAFAAAR+JAAAが行連鎖していることが分かる。
上記の連鎖行のINSERT文に対するREDOレコードを見てみよう。

SQL> select scn, row_id, data_obj#, operation, sql_redo,
     sql_undo from v$logmnr_contents;

SCN     ROW_ID               DATA_OBJ#  OPERATION  SQL_REDO                 SQL_UNDO
------- -------------------- ---------- ---------- ------------------------ ---------
687539  AAAAAAAAAAAAAAAAAA  0          INTERNAL             
687539   AAAAAAAAAAAAAAAAAA  0          INTERNAL             
687539   AAAAAAAAAAAAAAAAAA  0          START       set transaction read write;        
687539   AAAGW4AAFAAAR+IAAA  26040      INTERNAL             
687539   AAAAAAAAAAAAAAAAAA  0          INTERNAL             
687539   AAAGW4AAFAAAR+JAAA  26040      INTERNAL             
687541   AAAAAAAAAAAAAAAAAA  0          COMMIT      commit;        

上記のようにSQL_REDO列、SQL_UNDO列と共に空白になっている事がわかる。
また、ROW_IDは以下の2つのレコードが見られる。

・AAAGW4AAFAAAR+JAAA
・AAAGW4AAFAAAR+IAAA

1つのROW_ID(AAAGW4AAFAAAR+JAAA)が先程検索した行連鎖を起こしているROW_ID
と一致している。
また、ROW_ID(AAAGW4AAFAAAR+IAAA)に行連鎖していることが想像できる。

では、行移行の場合はどうなっているのか見てみたい。

まずはテーブルを作成し、1600バイトのデータを挿入し、
その後、1行のデータのUPDATEを行い、行移行を発生さる。

# テーブルからすべてのデータを削除

SQL> truncate table document;

Table truncated.

# 2バイトの行データを800件挿入(document_id列は1~800で一意)

SQL> begin
  2  for i in 1 .. 800 loop
  3  insert into document values(i,'n');
  4  end loop;
  5  end;
  6  /

# document_id=2 の行のROW_IDを取得

SQL> select rowid from document where document_id=2;

ROWID
------------------
AAAGYRAAFAAAR+DAAB

# document_id=2 の行のデータを1001バイトのデータにUPDATE

SQL> update document set document_data = '[n*1000]' where document_id=2;
                                   ※[n*1000]はnが1000文字をあらわしてる

# 行連鎖と同じ手順で行移行を確認

SQL> select table_name, head_rowid from chained_rows;

TABLE_NAME                     HEAD_ROWID
------------------------------ ------------------
DOCUMENT                       AAAGYRAAFAAAR+DAAB

# v$logmnr_contents表を検索

SQL> select scn, seg_name, row_id, operation, sql_redo from v$logmnr_contents;

SCN      SEG_NAME  ROW_ID              OPERATION  SQL_REDO
-------- --------- ------------------- ---------- ----------------------
799084             AAAAAAAAAAAAAAAAAA  START      set transaction read write;
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084             AAAAAAAAAAAAAAAAAA  INTERNAL        
799084   DOCUMENT  AAAGYRAAFAAAR+IAAA  INSERT        
799084   DOCUMENT  AAAGYRAAFAAAR+DAAB  DELETE     Unsupported (Chained Row)
799086             AAAAAAAAAAAAAAAAAA  COMMIT     commit;

結果を見るとDELETEの操作で、先程検索したdocument_idが2のデータのROW_ID
を削除しているのが分かる。また親切(?)にもサポートがされてないメッセー
ジもSQL_REDO列に表示されている。またOPERATION列がINSERTの行を見ると、
行の移行先のROW_IDにインサート処理を行なっている事が確認できる。

また、v$logmnr_contents表よりデータが含まれるデータファイルおよびブロッ
ク番号も確認できる。
では、ブロック番号を指定して行移行しているブロックのダンプを見てみよう。

SQL> select scn, row_id, operation, abs_file#,
     data_blk# from v$logmnr_contents;

SCN     ROW_ID              OPERATION    ABS_FILE#   DATA_BLK#
------- ------------------  ------------ ----------- -----------------
799083  AAAAAAAAAAAAAAAAAA  COMMIT       3           0
799084  AAAAAAAAAAAAAAAAAA  START        0           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           73603
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAAAAAAAAAAAAAAAA  INTERNAL     5           0
799084  AAAGYRAAFAAAR+IAAA  INSERT       5           73608
799084  AAAGYRAAFAAAR+DAAB  DELETE       5           73603
799086  AAAAAAAAAAAAAAAAAA  COMMIT       3           0

# 行移行元のブロックダンプを作成

SQL> alter system dump datafile 5 block 73603;

# 結果

 ---  ---
Block header dump:  0x01411f83
 ---  ---
block_row_dump:
tab 0, row 0, @0x7b0
tl: 8 fb: --H-FL-- lb: 0x0 cc: 2
col  0: [ 2]  c1 02
col  1: [ 1]  6e
tab 0, row 1, @0x273
tl: 9 fb: --H----- lb: 0x1 cc: 0
nrid:  0x01411f88.0
tab 0, row 2, @0x7a0
tl: 8 fb: --H-FL-- lb: 0x0 cc: 2
col  0: [ 2]  c1 04
col  1: [ 1]  6e
 ---  ---

ブロック・ヘッダー(Block header dump)を見てみると0x01411f83になっている。

また、ブロックの1行目(row 1)では列のデータが入っておらず、
nridが0x01411f88.0になっているのが分かる。
これはブロック・ヘッダーが0x01411f88の0行目(row 0)に移行していることを
指している。

では、行移行先のブロックダンプを見てみよう。

# 行移行先のブロックダンプを作成

SQL> alter system dump datafile 5 block 73608;

# 結果

 ---  ---
Block header dump:  0x01411f88
 ---  ---
block_row_dump:
tab 0, row 0, @0x3c2
tl: 1014 fb: ----FL-- lb: 0x1 cc: 2
hrid: 0x01411f83.1
col  0: [ 2]  c1 03
col  1: [999]
 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e
 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e 6e
 ---  ---

ブロックヘッダーは0x01411f88である。

ブロックの0行目(row 0)でhridが0x01411f83.1になっているのが分かる。
これはブロック・ヘッダーが0x01411f83の1行目(row 1)から移行されているこ
とを指している。

1行のデータを得るために2ブロックにアクセスする必要があるため、
パフォーマンスに悪影響を与えることがあらためて実感できる。

次回はログ・マイナーで索引構成表をみて見てみたい。

以上、サーフィン始めよう!の茅ヶ崎にて