Oracle 11g検証 Advanced Compression その5

投稿日: 2008年7月30日

<Oracle 11g検証 Advanced Compression その5>
ペンネーム: クリープ

今週も先週に引き続きダンプの解析を行います。
と、その前に、ちょっと話が長くなってきたので、先週までの流れをおさらい
しておきましょう。

本検証の第3回で、3種類のテーブル(通常テーブル、ダイレクト圧縮テーブル、
Advanced Compressionテーブル)にINSERT文を実行したところ、以下のように
ダイレクト圧縮テーブルよりAdvanced Compressionテーブルの方がサイズが大
きくなっていたことが判明しました。

TABLE_NAME               size(KB)
---------------------- ----------
COMP_TABLE_NORMAL            2974
COMP_TABLE_DIRECT            1362
COMP_TABLE_ADVANCED          1966

何故ダイレクト圧縮テーブルとAdvanced Compressionテーブルのサイズに差異
が発生したのか?という原因を調査する為、各テーブルのダンプを取得しまし
た。すると、ブロックに格納されている行数に差異があることがわかりました。

通常テーブル                : 86行
ダイレクト圧縮テーブル      :169行
Advanced Compressionテーブル:148行

1ブロックに格納される行数に差異が発生する原因を解明する為、現在、各
テーブルのダンプに出力されている行の情報を解析して原因を探っています。
先週は、通常テーブルとダイレクト圧縮テーブルの途中まで解析を実施し、通
常テーブルよりダイレクト圧縮テーブルの方が1行のバイト長が小さいところ
まで確認しました。
今週はダイレクト圧縮テーブルではどのようにして1行のバイト長を小さくし
ているのか?そのメカニズムについて解析していきます。

■■■■■概要■■■■■
1.ダイレクト圧縮テーブルのダンプ(おさらい)
2.bindmp解析
※「Advanced Compressionテーブルの解析」は来週実施

■環境
RedHat Enterprise Linux ES4 Update 5
Oracle Database 11g Enterprise Edition Release 11.1.0.6 – Production

1.ダイレクト圧縮テーブルのダンプ(おさらい)
まずは、先週行ったダイレクト圧縮テーブルのブロック・ダンプの解析をおさ
らいしましょう。

・ダイレクト圧縮テーブルのブロック・ダンプ

     1  block_row_dump:
     2  tab 0, row 0, @0x773
     3  tl: 13 fb: --H-FL-- lb: 0x0  cc: 1
     4  col  0: [10]  30 30 30 30 30 30 30 30 30 30
     5  bindmp: 00 a8 d2 30 30 30 30 30 30 30 30 30 30
     6  tab 1, row 0, @0x76a
     7  tl: 9 fb: --H-FL-- lb: 0x0  cc: 2
     8  col  0: [10]  30 30 30 30 30 30 30 30 30 30
     9  col  1: [ 3]  c2 18 1e
    10  bindmp: 2c 00 02 01 00 cb c2 18 1e
    11  tab 1, row 1, @0x761
    12  tl: 9 fb: --H-FL-- lb: 0x0  cc: 2
    13  col  0: [10]  30 30 30 30 30 30 30 30 30 30
    14  col  1: [ 3]  c2 18 1f
    15  bindmp: 2c 00 02 01 00 cb c2 18 1f
     :
     :  (省略)
     :
    16  tab 1, row 166, @0x196
    17  tl: 9 fb: --H-FL-- lb: 0x0  cc: 2
    18  col  0: [10]  30 30 30 30 30 30 30 30 30 30
    19  col  1: [ 3]  c2 0f 40
    20  bindmp: 2c 00 02 01 00 cb c2 0f 40
    21  tab 1, row 167, @0x18d
    22  tl: 9 fb: --H-FL-- lb: 0x0  cc: 2
    23  col  0: [10]  30 30 30 30 30 30 30 30 30 30
    24  col  1: [ 3]  c2 0f 41
    25  bindmp: 2c 00 02 01 00 cb c2 0f 41
    26  end_of_block_dump

まずは、7行目を見て下さい。「tl: 9」とあり、この行が9bytesで格納されて
いることがわかります。
ここで、通常テーブルのバイト長を思い出してください。

    ・1行当たりのバイト長
      行ヘッダー情報のサイズ               3バイト
      列の長さ                             2バイト
       1番目のカラム(SEQ_NO)のバイト長     3バイト
    +  2番目のカラム( MSG)のバイト長      10バイト
    -----------------------------------------------
                                          18バイト

通常テーブルの行数は上記計算式により18bytesでした。
つまり、ダイレクト圧縮テーブルが通常テーブルよりも9bytes短くなっている
ことがわかります。では、通常テーブルでは18bytesだったデータをダイレク
ト圧縮テーブルではどのようにして9bytesにしているのでしょうか?

ダンプをさらに読み進めてみると、8、9行目の「col 0」、「col 1」の下に
通常テーブルにはなかったbindmpという行があります。通常テーブルには存在
していなかった、ということはこの行に圧縮された情報が格納されているので
は!?
と、この行をさらによく見てみると16進数の値が9つ並んでおり、「tl: 9」の
値と一致しているではありませんか!

    行           1  2  3  4  5  6  7  8  9
    --------------------------------------
    10  bindmp: 2c 00 02 01 00 cb c2 18 1e
    15  bindmp: 2c 00 02 01 00 cb c2 18 1f
    20  bindmp: 2c 00 02 01 00 cb c2 18 20
    25  bindmp: 2c 00 02 01 00 cb c2 0f 40
    30  bindmp: 2c 00 02 01 00 cb c2 0f 41

つまり、このbindmpという行にある16進数の値がまさに圧縮された行のデータ、
という可能性が高そうです。
ということで、このbindmpの値についてさらに詳しく見ていくことにしましょ
う。

2.bindmp解析
ではまず「1」の値ですが、マニュアル「Oracle Database 概要( 11g リリー
ス 1)」の記述によれば、行情報の先頭3bytesは行ヘッダーの情報ということ
でした。ダイレクト圧縮テーブルでも同様であれば、「1」から「3」までは行
ヘッダーの情報が格納されていることになります。

次に少し飛んで「7」から「9」までを見てください。これらは「 col 1」の値
と一致します。つまり、この値はSEQ_NOカラムのデータのようです。

ということは、残る「4」から「6」は、消去法でいけばMSGカラムのデータに
相当すると考えられます。MSGカラムには10bytesの値を格納しているので、当
然3bytesで表すことは不可能です。ということは、この3bytesでシンボル表を
参照する為の情報が格納されていると考えられます。
では、「4」から「6」にどのような値が格納されているのでしょうか?

これを確かめるために、カラム数と値の種類を増やしたテーブルを作成し、再
度ブロック・ダンプを取得してみます。データの種類が増えれば、シンボル表
に登録される重複値の種類にも幅が出るので、シンボル表への参照数にも違い
が出るはずです。ひいては、どのようにして参照しているのかについてもわか
るかもしれません。

ということで、テーブル作成!

SQL> create table msg_column5
  2  ( seq_no number,
  3    msg1 varchar2(5),
  4    msg2 varchar2(5),
  5    msg3 varchar2(5),
  6    msg4 varchar2(5),
  7    msg5 varchar2(5),
  8    primary key(seq_no) )
  9  compress for direct_load operations;

Table created.

このテーブルは、今までの検証で使用していた comp_table_directテーブルに
「 msg(番号)」というカラムを 4つ追加したものです。これらのカラムに 4種
類のデータをinsertしてブロック・ダンプを取得してみましょう。
では、データINSERT!

SQL> insert /*+ append */ into msg_column5
  2  select seq_no,
  3   lpad( mod(seq_no,4),5,'0' ),
  4   lpad( mod(seq_no,4),5,'0' ),
  5   lpad( mod(seq_no,4),5,'0' ),
  6   lpad( mod(seq_no,4),5,'0' ),
  7   lpad( mod(seq_no,4),5,'0' )
  8  from comp_table_normal;

100000 rows created.

SQL> commit;

Commit complete.

SQL> select segment_name,file_id,block_id,blocks
  2    from dba_extents
  3   where segment_name = 'MSG_COLUMN5'
  4     and owner = 'TEST'
  5     and extent_id = 0;

SEGMENT_NAME                           FILE_ID   BLOCK_ID     BLOCKS
----------------------------------- ---------- ---------- ----------
MSG_COLUMN5                                  4      14177         32

SQL> alter system dump datafile 4 block min 14177 block max 14209;

System altered.

・msg_column5のダンプ

     1  block_row_dump:
     2  tab 0, row 0, @0x750
     3  tl: 8 fb: --H-FL-- lb: 0x0  cc: 5
     4  col  0: [ 5]  30 30 30 30 31
     5  col  1: [ 5]  30 30 30 30 31
     6  col  2: [ 5]  30 30 30 30 31
     7  col  3: [ 5]  30 30 30 30 31
     8  col  4: [ 5]  30 30 30 30 31
     9  bindmp: 00 29 05 04 04 04 04 04
    10  tab 0, row 1, @0x758
    11  tl: 8 fb: --H-FL-- lb: 0x0  cc: 5
    12  col  0: [ 5]  30 30 30 30 30
    13  col  1: [ 5]  30 30 30 30 30
    14  col  2: [ 5]  30 30 30 30 30
    15  col  3: [ 5]  30 30 30 30 30
    16  col  4: [ 5]  30 30 30 30 30
    17  bindmp: 00 29 05 07 07 07 07 07
    18  tab 0, row 2, @0x740
    19  tl: 8 fb: --H-FL-- lb: 0x0  cc: 5
    20  col  0: [ 5]  30 30 30 30 33
    21  col  1: [ 5]  30 30 30 30 33
    22  col  2: [ 5]  30 30 30 30 33
    23  col  3: [ 5]  30 30 30 30 33
    24  col  4: [ 5]  30 30 30 30 33
    25  bindmp: 00 28 05 06 06 06 06 06
    26  tab 0, row 3, @0x748
    27  tl: 8 fb: --H-FL-- lb: 0x0  cc: 5
    28  col  0: [ 5]  30 30 30 30 32
    29  col  1: [ 5]  30 30 30 30 32
    30  col  2: [ 5]  30 30 30 30 32
    31  col  3: [ 5]  30 30 30 30 32
    32  col  4: [ 5]  30 30 30 30 32
    33  bindmp: 00 28 05 05 05 05 05 05
    34  tab 0, row 4, @0x770
    35  tl: 8 fb: --H-FL-- lb: 0x0  cc: 1
    36  col  0: [ 5]  30 30 30 30 31
    37  bindmp: 00 05 cd 30 30 30 30 31
    38  tab 0, row 5, @0x768
    39  tl: 8 fb: --H-FL-- lb: 0x0  cc: 1
    40  col  0: [ 5]  30 30 30 30 32
    41  bindmp: 00 05 cd 30 30 30 30 32
    42  tab 0, row 6, @0x760
    43  tl: 8 fb: --H-FL-- lb: 0x0  cc: 1
    44  col  0: [ 5]  30 30 30 30 33
    45  bindmp: 00 05 cd 30 30 30 30 33
    46  tab 0, row 7, @0x778
    47  tl: 8 fb: --H-FL-- lb: 0x0  cc: 1
    48  col  0: [ 5]  30 30 30 30 30
    49  bindmp: 00 05 cd 30 30 30 30 30
    50  tab 1, row 0, @0x737
    51  tl: 9 fb: --H-FL-- lb: 0x0  cc: 6
    52  col  0: [ 5]  30 30 30 30 30
    53  col  1: [ 5]  30 30 30 30 30
    54  col  2: [ 5]  30 30 30 30 30
    55  col  3: [ 5]  30 30 30 30 30
    56  col  4: [ 5]  30 30 30 30 30
    57  col  5: [ 3]  c2 20 4d
    58  bindmp: 2c 00 02 05 01 cb c2 20 4d
    59  tab 1, row 1, @0x72e
    60  tl: 9 fb: --H-FL-- lb: 0x0  cc: 6
    61  col  0: [ 5]  30 30 30 30 31
    62  col  1: [ 5]  30 30 30 30 31
    63  col  2: [ 5]  30 30 30 30 31
    64  col  3: [ 5]  30 30 30 30 31
    65  col  4: [ 5]  30 30 30 30 31
    66  col  5: [ 3]  c2 20 4e
    67  bindmp: 2c 00 02 05 00 cb c2 20 4e
     :  
     :  (省略)
     :  
    68  tab 1, row 160, @0x199
    69  tl: 9 fb: --H-FL-- lb: 0x0  cc: 6
    70  col  0: [ 5]  30 30 30 30 30
    71  col  1: [ 5]  30 30 30 30 30
    72  col  2: [ 5]  30 30 30 30 30
    73  col  3: [ 5]  30 30 30 30 30
    74  col  4: [ 5]  30 30 30 30 30
    75  col  5: [ 3]  c2 22 25
    76  bindmp: 2c 00 02 05 01 cb c2 22 25
    77  tab 1, row 161, @0x190
    78  tl: 9 fb: --H-FL-- lb: 0x0  cc: 6
    79  col  0: [ 5]  30 30 30 30 31
    80  col  1: [ 5]  30 30 30 30 31
    81  col  2: [ 5]  30 30 30 30 31
    82  col  3: [ 5]  30 30 30 30 31
    83  col  4: [ 5]  30 30 30 30 31
    84  col  5: [ 3]  c2 22 26
    85  bindmp: 2c 00 02 05 00 cb c2 22 26

それでは、tab 1, row 0のbindmpを並べて、「4」から「6」までを順に比較し
ていきましょう。

    行                              1  2  3  4  5  6  7  8  9
    ---------------------------------------------------------
    10 comp_table_direct   bindmp: 2c 00 02 01 00 cb c2 18 1e
    58 msg_column5         bindmp: 2c 00 02 05 01 cb c2 20 4d

まず「6」ですが、双方ともcbなので、値に変化は見られません。つまり、こ
こには圧縮データへの参照情報は格納されていない為、比較対象から除外して
もよさそうです。
次に、「4」ですが、comp_table_directテーブルが01になっているのに対して
msg_column5テーブルは05です。05という値、これはmsg_column5テーブルの圧
縮されたカラムの数と一致しています。

念のため、msgカラムの数を10に増やしたテーブルのダンプを取得してみたと
ころ、0aとなっていました。0aは10進数に直すと10なので、「4」はカラム数
であることがわかります。

                                 1  2  3  4  5  6  7  8  9
    ------------------------------------------------------
    msg_column10        bindmp: 2c 00 02 0a 01 cb c2 20 4d

そして「5」。msg_column5テーブルの値を見ると、01のものと00の2種類が格
納されていました。

    行                           1  2  3  4  5  6  7  8  9
    ------------------------------------------------------
    58                  bindmp: 2c 00 02 05 01 cb c2 20 4d
    67                  bindmp: 2c 00 02 05 00 cb c2 20 4e
    76                  bindmp: 2c 00 02 05 01 cb c2 22 25
    85                  bindmp: 2c 00 02 05 00 cb c2 22 26

ではどのようにシンボル表を参照しているのでしょうか?
よく見ると、この値、シンボル表の行番号と対応していることがわかります。
たとえば、58行目の01という値に格納されている値は、シンボル表の行番号1
(8行目の「tab 0, row 1」)に格納されている値と一致しており、67行目の0
0は、シンボル表の行番号0(2行目の「tab 0, row 0」)に格納されている値
と一致しています。
つまり、「5」はシンボル表の行番号が格納されており、これを使用してシン
ボル表を参照している、ということになります。

さらに、「tab 0, row 1」のbindmpを見ると、「4」から「8」の値が04になっ
ています。

    行                           1  2  3  4  5  6  7  8
    ---------------------------------------------------
     9                  bindmp: 00 29 05 04 04 04 04 04

この04という値は、「tab 0, row 4」を表しています。つまり、シンボル表の
中でも圧縮できるところは圧縮して格納している、ということのようです。
サイズを小さくする為に、Oracleは内部で色んな工夫をしているんですね。

以上で、bindmpに格納されている内容が理解できました。
それではいよいよAdvanced Compressionテーブルのダンプ!と行きたいところ
ですが、Advanced Compressionテーブルのダンプは来週解析することにしま
しょう。
それではまた来週!

インサイト禁煙ブーム蔓延中!これってTASPO効果!?
恵比寿にて