トランザクションエントリに関する検証 その5

<トランザクションエントリに関する検証 その5>
ペンネーム しゅらん

今週も引き続きテーブルやインデックスを作成する際に設定するinitrans、
maxtransについて検証をします。

検証環境
OS:Windows2000 Server
Oracle:8.1.7
DB_BLOCK_SIZE:8K

先週は読者からの質問に関する検証を行いました。

(質問内容)
現在、ブロックに幾つトランザクションエントリが
作成されているか?幾つ増えたかを知る方法はあるのでしょうか?

ダンプを取って、トランザクションエントリ(ITL)の情報を確認したところ、
一度作成されたトランザクションエントリ情報はコミットしても、テーブルの
トランケートを行っても、Oracleの再起動を行っても情報として残っていまし
た。

これは履歴として残っているだけなのか、一度領域として利用された場合、
2度とデータ用の領域として再利用されることはないのか、読者からの質問の
内容と少々ズレてきているが、検証してみましょう。

先週は以下のテーブルに169セッションから同時insertを行い、ブロックの
ダンプを取ったところまで確認しました。

 tbl_shu4
 ----------------------------------------- -------- ----------------------------
 TEXT                                               VARCHAR2(1000)

ダンプを取って確認
 Itl           Xid                  Uba                      Flag  Lck        Scn/Fsc
0x01   xid:  0x0001.012.00000052    uba: 0x00800158.000e.23  --U-    1  fsc 0x0000.0004832d
0x02   xid:  0x0002.037.00000050    uba: 0x00800375.0005.2b  --U-    1  fsc 0x0000.0004832f
・・・・・・・・・・・・・・・
0xa8   xid:  0x0012.018.00000052    uba: 0x00802277.0013.01  --U-    1  fsc 0x0000.00048458
0xa9   xid:  0x0013.027.00000050    uba: 0x0080250c.0004.01  --U-    1  fsc 0x0000.00048459

合計169個のトランザクションエントリが作成されていた。

—トランザクションエントリの解放—

今週はこのテーブルに何バイトのデータが挿入可能かを検証します。

計算上ではトランザクションエントリの部分が再利用される場合と、されない
場合では3887Bytes(23バイト*169)の差が出るはずである。

initransが1のときの通常の利用可能領域の計算式(0.9はpctfree(10%)を考慮)
CEIL((ブロックサイズ8192-ブロックヘッダ86)×0.9) – 4 = 7292Bytes
約7300バイト程度はデータ用領域として使用できるはずである。

—トランザクションエントリが残っており、
そのエントリを使用したデータが残っている場合—

現在、1バイトのデータを169レコードインサートしており、その使用領域は
行ヘッダーやカラム情報等のオーバヘッド等を考慮すると1859Bytesになる。

つまりトランザクションエントリが解放される場合、
7292-1859=5443Bytes が追加で使用できるデータ用領域となり、
解放されない場合は
7292-1859-3887=1546Bytesが追加で使用できるデータ用領域となる。

この状態のブロックにvarchar2(1000)のカラムに1000バイトのデータを
セットして1つのセッションから10行をインサートしてみる。

この状態で上記169のトランザクションエントリが作成されていたブロックの
ダンプを再度取得。結果は・・・

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   xid:  0x0019.017.00000052    uba: 0x00803160.0005.02  --U-    1  fsc 0x0000.0004a909
0x02   xid:  0x0012.049.00000053    uba: 0x0080230b.0014.02  C---    0  scn 0x0000.0004a79a
・・・・・・・・・
0xa8   xid:  0x0005.008.00000051    uba: 0x008008d3.0003.01  C---    0  scn 0x0000.0004a8cd
0xa9   xid:  0x0006.038.00000051    uba: 0x00800b8b.0006.01  C---    0  scn 0x0000.0004a8cc
・・・・・・・・・
nrow=170   ←   格納されている行数

170-169=1行しか格納されていない!

—トランザクションエントリが残っているが、
そのエントリを使用したデータはtruncateされ、残っていない場合—

次に、このテーブルをtruncateして同じようにvarchar2(1000)のカラムに1000
バイトのデータをセットして1つのセッションから10行をインサートしてみる。

truncate直後のダンプ、ITLが残っている状態

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   xid:  0x0019.017.00000052    uba: 0x00803160.0005.02  --U-    1  fsc 0x0000.0004a909
0x02   xid:  0x0012.049.00000053    uba: 0x0080230b.0014.02  C---    0  scn 0x0000.0004a79a
・・・・・・・・・・・・・・
0xa8   xid:  0x0005.008.00000051    uba: 0x008008d3.0003.01  C---    0  scn 0x0000.0004a8cd
0xa9   xid:  0x0006.038.00000051    uba: 0x00800b8b.0006.01  C---    0  scn 0x0000.0004a8cc

10行インサート後のダンプ

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   xid:  0x001c.058.00000051    uba: 0x008037a7.0006.0a  --U-    7  fsc 0x0000.0004a913
・・・・・・・・・・・・・・
nrow=7

7行が格納され、トランザクションエントリは1つに減っていた。

—結論—

169セッションから同時にインサートをした場合、トランザクションエントリは
残ったままになっていた。これはそのトランザクションエントリを使用して
格納を行ったデータが残っている場合、それぞれのレコードが他のセッション
から再度同時に別々に操作される可能性を考慮し、同時に必要となるトランザ
クションエントリを確保しておく。この場所の確保を指してプレースホルダー
と呼ぶ。これにより、レコードをロックしようとして、ブロックロックが掛か
ってしまうことを防いでいると考えられる。

また、truncateされてしまった場合トランザクションエントリもリセットされ
ているのは、もちろん領域の解放という意味もあるが、次にそのブロックに格
納されるデータがもしかしたら7レコードかもしれない。そのブロックに169も
のトランザクションエントリが残っていたとしても何の意味も成さず、領域の
無駄遣いとなるだけであるためと納得できる。

次回も引き続きトランザクションエントリに関する検証を行います。

以上、フィッシャーマンの釣った40キロのマグロをもらって嬉しい茅ヶ崎にて