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

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

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

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

—maxtransに関する検証 ブロック格納率—

tbl_shu1,tbl_shu2の定義

ID               DATE
TEXT             CHAR(10)

前回はmaxtransを1 に設定して、200同時sessionにてインサートを行うとどう
なるかの検証をしました。

select TABLE_NAME,NUM_ROWS,BLOCKS from dba_tables
where table_name='TBL_SHU1';

TABLE_NAME                       NUM_ROWS     BLOCKS
------------------------------ ---------- ----------
TBL_SHU1                           200000     148989

上記のように1ブロックに2レコードも格納されていない結果となった。

また、3つのsessionから同時にinsertを行い、結果を確認するとやはり3つの
ブロックを使用していた。

select TABLE_NAME,NUM_ROWS,BLOCKS from dba_tables
where table_name='TBL_SHU2';

TABLE_NAME                       NUM_ROWS     BLOCKS
------------------------------ ---------- ----------
TBL_SHU2                                3          3

このことから、ブロック内のトランザクションエントリがmaxtransの値に達す
ると、Oracleは次のトランザクションを待たせないために、ハイウォーターマ
ークを引き上げ、新しいブロックを割り当てている事が分かった。

今回はブロック内の残ったスペース、フリーリスト(次のレコードの挿入先)
について検証を行います。

—ダンプファイル—

フリーリストやハイウォーターの情報はセグメントヘッダーで管理しているの
でセグメントヘッダーのダンプを取って、確認をしてみましょう。

SQL> select file_id,block_id from dba_extents
where segment_name = 'TBL_SHU2' and extent_id=0;

FILE_ID   BLOCK_ID
---------- ----------
7          2

SQL> alter system dump datafile 7 block 2;

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

(注)このコマンドはoracleのinternalなコマンドでサポートの対象外にもなっ
ているので、使用する際にはご注意下さい。

(dumpより抜粋)

?buffer tsn: 6 rdba: 0x01c00002 (7/2)
?Highwater::  0x01c00006  ext#: 0      blk#: 3      ext size: 2559
?SEG LST:: flg: USED   lhd: 0x01c00005 ltl: 0x01c00005

?のrdbaはこのブロックのデータブロックアドレス(以下DBA)
?のHighwaterはハイウォーターマークのDBA(ハイウォーターはデータが入っ
ている最後のブロックの1個先を示している)
?のlhdはフリーリストの最初の空きブロックのDBA

つまり現在のブロックの状況は以下のようになっている。

0x01c00002 segment header
0x01c00003 datablock 1
0x01c00004 datablock 2
0x01c00005 datablock 3
0x01c00006 highwater の指すブロック

?のlhdはdatablock 3 を指し示しているため、次にinsertするときには
datablock 3 に実際のデータが格納されることになる。

またdatablockのdumpも見てみよう。

0x01c00003 seg/obj: 0xc67  csc: 0x00.3f226  itc: 1  flg: -  typ: 1 - DATA
0x01c00004 seg/obj: 0xc67  csc: 0x00.3f227  itc: 1  flg: -  typ: 1 - DATA
0x01c00005 seg/obj: 0xc67  csc: 0x00.3f228  itc: 1  flg: O  typ: 1 - DATA

datablock1,2はflgが-(ハイフン)になっているが、datablock3はflgがOにな
っている。これもdatablock1,2がフリーリストから外れていることを示す。

これはつまり、3sessionで同時にinsertを行い、2つ目、3つ目ののsessionは
datablock1,2に対して挿入を行おうとしたが、トランザクションエントリを使
い切ったことにより、挿入が出来なかった。

これによりこのブロックは既に満杯という判断をoracleが下し、フリーリス
トから外れてしまったということであろう。

では実際にinsertを行ってみる。

(実行)insert into tbl_shu2 (TEXT) values ('PPPPPPPPPP');

再度ブロックダンプを取って、確認。
insert前

0x01c00005 nrow=1

insert後

0x01c00005 nrow=2

やはりdatablock3に格納された。

それではこのdatablock1,2は再利用されないのであろうか。

一度フリーリストから外れたブロックが再度フリーリストに組み込まれるには
対象のブロックに収まっているレコードのdeleteやupdateが行われ、その時点
でpctusedを下回った場合に再度フリーリストに組み込まれる。

SQL> delete from tbl_shu2
2  where to_char(id,'MM/DD HH24:MI:SS')='03/19 16:01:55';

1行が削除されました。

SQL> commit;

SQL> alter system dump datafile 7 block 3;
0x01c00003 seg/obj: 0xc67  csc: 0x00.443a3  itc: 1  flg: O  typ: 1 - DATA

このように、flgがOに変わっていることが分かる。

そのため、insertしか行われないテーブルは再利用が行われず、無駄な領域だ
らけになってしまう。

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

以上、桜の開花が待ち遠しい茅ヶ崎にて