PageとRecord (2)

今朝はrow_format=redundantの時にold styleであることの当たりをつけたので、今度はrow_format=compactで作成したテーブルのhexdumpを解析しませう。

DDLおよびDMLは以下。row_format=compactはデフォルト値なので別に付与しなくとも良いけど気分的に。

create table t_compact (
  c1 int primary key, c2 char(10) charset latin1
  ) engine = innodb row_format = compact;

insert into t_compact values
(1, '1111'),
(2, '2222'),
(16, '3333'),     
(8, '4444');

dumpデータはこちら:http://ikda.net/resource/mysql/ibdata1_hd2

該当Pageのhexdumpは以下。HEXのパターンからなんとなくで各レコード(と思われる範囲)に色をつけてみた。

000cfff0  00 00 00 00 00 74 00 65  75 4e 3f 5d 00 00 fa 99  |.....t.euN?]...|
000d0000  df c5 80 64 00 00 00 34  ff ff ff ff ff ff ff ff  |.d...4|
000d0010  00 00 00 00 00 01 21 4b  45 bf 00 00 00 00 00 00  |......!KE......|
000d0020  00 00 00 00 00 00 00 02  00 fc 80 06 00 00 00 00  |...............|
000d0030  00 e1 00 05 00 00 00 04  00 00 00 00 00 00 00 00  |...............|
000d0040  00 00 00 00 00 00 00 00  00 1a 00 00 00 00 00 00  |................|
000d0050  00 02 15 f2 00 00 00 00  00 00 00 02 15 32 01 00  |............2..|
000d0060  02 00 1b 69 6e 66 69 6d  75 6d 00 05 00 0b 00 00  |...infimum......|
000d0070  73 75 70 72 65 6d 75 6d  00 00 00 10 00 21 80 00  |supremum.....!..|
000d0080  00 01 00 00 00 00 19 06  80 00 00 00 2d 01 10 61  |............-..a|
000d0090  61 61 61 20 20 20 20 20  20 00 00 00 18 00 42 80  |aaa      .....B.|
000d00a0  00 00 02 00 00 00 00 19  06 80 00 00 00 2d 01 1c  |.............-..|
000d00b0  62 62 62 62 20 20 20 20  20 20 00 00 00 20 ff b0  |bbbb      ... |
000d00c0  80 00 00 10 00 00 00 00  19 06 80 00 00 00 2d 01  |..............-.|
000d00d0  28 63 63 63 63 20 20 20  20 20 20 00 00 00 28 ff  |(cccc      ...(|
000d00e0  df 80 00 00 08 00 00 00  00 19 06 80 00 00 00 2d  |..............-|
000d00f0  01 34 64 64 64 64 20 20  20 20 20 20 00 00 00 00  |.4dddd      ....|
000d0100  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

ちょっとこの部分に絞って見てみよう。

000d0090  61 61 61 20 20 20 20 20  20 00 00 00 18 00 42 80  |aaa      .....B.|
000d00a0  00 00 02 00 00 00 00 19  06 80 00 00 00 2d 01 1c  |.............-..|
000d00b0  62 62 62 62 20 20 20 20  20 20 00 00 00 20 ff b0  |bbbb      ... |

経験的にパッと分かるのは、0x000d009fから0x000d00a3にかけての"80 00 00 02"が主キーの値であるc1=2、次の6バイト分"00 00 00 00 19 06"がトランザクションID、その次の7バイト分"80 00 00 00 2d 01 1c"がロールポインタ、そこから先がc2="bbbb"ということ。

しかしさて、こうなるとちょっと困ってしまった。

00 00 00 18 00 42

Record Headerと呼べる部分がこれしか無いことになる。

ちょっと並べてみよう。

c1=1  00 00 00 10 00 21
c1=2  00 00 00 18 00 42
c1=16 00 00 00 20 ff b0
c1=8  00 00 00 28 ff df

まずは逆順先頭2バイトが持っているPage内での相対ポインタに注目。

少しかじった知識によると、このPage内のレコードのポインタは以下の順序で次のレコードを指している。

infimum → c1=1 → c1=2 → c1=8 → c1=16 → supremum

でもって相対ポインタなので、、、

  • c1=1の"00 21"は次のレコードの相対位置が+33であることを意味
  • c1=2の"00 42"は次のレコードの相対位置が+66であることを意味
  • c1=16の"ff b0"は次のレコードの相対位置が-80であることを意味
  • c1=8の"ff df"は次のレコードの相対位置が-33であることを意味

というわけで、これを元にhexdumpを見直してみると、ちゃんと予想した通りのdumpになっている。

問題はグレー以外の残りの部分。どうみてもRecord Offset情報は記述されていない。

c1=1  00 00 00 10 00 21
c1=2  00 00 00 18 00 42
c1=16 00 00 00 20 ff b0
c1=8  00 00 00 28 ff df

次のbyteの下位3bitがレコードの種類なのだけれども、

0x10 = 0001 0000
0x18 = 0001 1000
0x20 = 0010 0000
0x28 = 0010 1000

ということで、4つとも"000"であり、Record Typeは"Conventional"ということになる。これも筋が通る。

ちなみにsupremumレコードのRecord Typeは0x0bの下位3bitということで"0000 1011"により"011"であり、rem0rec.cのコメント通りsupremum型となっている。

infimumレコードも0x02の下位3bitということで"010"となることからinfimum型である。

ついでにsupremumの相対ポインタの値は"00 00"、infinumの相対ポインタの値は"00 1b"(+27)ということでバッチリだ。

次は13bitで表現されたindex page内のheapにおけるレコード番号というものなのだけれども、ちょっと整理。青が相対ポインタ、緑がレコード型、橙がレコード番号。

infinum  = 32 01 00 02 00 1b = 0011 0010 0000 0001 0000 0000 0000 0010 0000 0000 0001 1011
supremum = 00 05 00 0b 00 00 = 0000 0000 0000 0101 0000 0000 0000 1011 0000 0000 0000 0000
c1=1     = 00 00 00 10 00 21 = 0000 0000 0000 0000 0000 0000 0001 0000 0000 0000 0010 0001
c1=2     = 00 00 00 18 00 42 = 0000 0000 0000 0000 0000 0000 0001 1000 0000 0000 0100 0010
c1=16    = 00 00 00 20 ff b0 = 0000 0000 0000 0000 0000 0000 0010 0000 1111 1111 1011 0000
c1=8     = 00 00 00 28 ff df = 0000 0000 0000 0000 0000 0000 0010 1000 1111 1111 1110 1111

この13bitは単純にPage内でのレコード番号を意味しており、、というかこの場所自身がIndex PageのHeapってことなんかな。INSERTされた順序とかで付与されるっぽい。

続いて赤色の部分が、recordのn_owned。infinumとsuprenumには1とか5とか付いてるけど、普通のレコードには今のところついていない。

続いて灰色の部分が、deleteされたかどうかのマーク。とりあえずどれも生きてるから0らしい。次はdeleteしてみてhexdumpを確認してみるか。GCされる前にやらんと見えないと思うけど。

最後は黒の部分。ソースコメントによれば、

SQL-null flags (1 bit per nullable field), padded to full bytes

ということで値がNULLの場合にはbitが立つとか。複数カラムあったらどうすんだ?とか今のところ意味不明。infinumだけなんか値入ってるし。

ソースコメントによれば最後の最後、

length of the last non-null variable-length field of data:
if the maximum length is 255, one byte; otherwise, 0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes, length=128..16383, extern storage flag) | ...
length of first variable-length field of data
あー、なるほど、そういうことか。可変長カラム以外はデータディクショナリから解決するようになったってことか>"new style"。 今回は固定長データ型しか使ってないからこうなのね。文章ちゃんと読めてないだけという落ちw ということでとりあえず完了。row_format=compactのときにnew styleでしたね。ということは、ver4.1系、ver5.0系ともに、古いバージョンを使っている人以外はみんなnew styleってことでつね。MySQL Internals Manualの役立たずがっ!!w おいらの6時間をかえせーw 今朝早かったのできょうはここでおしまい。おやすみなさーい。