Tuesday, September 15, 2009

INITRANSとMAXTRANS

セグメントの属性中同時トランザクション数を制御するINITRANSとMAXTRANSパラメータは歴史的な理由で正確な動作方式が混乱な面があります。最近のバージョンの動作方式は次のとおりです。

  • INITRANSの基本値は2で最小値も2であります。ただ、ディクショナリー(ALL_TABLESなど)には”1”の値で観察されます。でも実際の値は2であります。
  • MAXTRANSの基本値は255であり最小値の255であります。すなわち固定値です。

ここで二つの面白い質問ができます。

  1. INITRANSの実際の基本値が”1”ではなくて”2”だというのをどうすれば証明できるだろうか。
  2. MAXTRANSの値を255ではなくてもっと低くする方法はないだろうか。(255より大きい値にするのは不可能です。1バイトで表現できる最大の値だからです)

簡単なデモを通じて答えをみます。


まず次のようにテーブルを一つ作ります。INITRANS値とMAXTRANS値を各々1と5で指定しています。しかしディクショナリーには1,255で指定されているのがわかります。


UKJA@ukja1021> create table t1(c1 int)
2 initrans 1 -- 1!
3 maxtrans 5 -- 5!
4 ;

Table created.

Elapsed: 00:00:00.03
UKJA@ukja1021>
UKJA@ukja1021> select table_name, ini_trans, max_trans
2 from user_tables where table_name = 'T1';

TABLE_NAME INI_TRANS MAX_TRANS
-------------------- ---------- ----------
T1 1 255

Elapsed: 00:00:00.01
UKJA@ukja1021>
UKJA@ukja1021> insert into t1 select level from dual connect by level <= 10;

10 rows created.

Elapsed: 00:00:00.01
UKJA@ukja1021> commit;

Commit complete.

Elapsed: 00:00:00.00

一つのトランザクションを発生してからブロックダンプを修行してみます。

UKJA@ukja1021> col f# new_value fno
UKJA@ukja1021> col b# new_value bno
UKJA@ukja1021>
UKJA@ukja1021> select dbms_rowid.rowid_relative_fno(rowid) f#,
2 dbms_rowid.rowid_block_number(rowid) b#
3 from t1
4 where rownum <= 1;

F# B#
---------- ----------
8 9011

Elapsed: 00:00:00.01
UKJA@ukja1021>
UKJA@ukja1021> update t1 set c1 = 1 where c1 = 1;

1 row updated.

Elapsed: 00:00:00.00

次のように2個のITLエントリが登録されているのを見られます。今まで最大一つのトランザクションだけを発生させたのでINITRANSの実際値が2であるのが分かります。

UKJA@ukja1021> alter system dump datafile &fno block &bno;
old 1: alter system dump datafile &fno block &bno
new 1: alter system dump datafile 8 block 9011

System altered.

Elapsed: 00:00:00.01

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0005.017.000004d6 0x0080095b.01ca.19 C--- 0 scn 0x0000.0015f76c
0x02 0x0004.008.00000370 0x008001b8.0181.26 ---- 1 fsc 0x0000.00000000

さて次のように5個のトランザクションをさらに発生させます。

UKJA@ukja1021> ho type temp.sql
update t1 set c1 = &1 where c1 = &1;

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 2

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 3

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 4

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 5

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 6

MAXTRANSの値を5で指定したからこの設定が動作したら6番目のトランザクションは待機状態に落ち込まなければなりません。でも、次のように全部で6個のITLエントリが成功的に登録され、すべてのトランザクションが待機なしに成功的に修行されます。MAXTRANSは255という固定値を使用するからです。

UKJA@ukja1021> alter system dump datafile &fno block &bno;
old 1: alter system dump datafile &fno block &bno
new 1: alter system dump datafile 8 block 9011

System altered.

Elapsed: 00:00:00.06

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x000a.003.00000365 0x00800430.0212.0c ---- 1 fsc 0x0000.00000000
0x02 0x0004.008.00000370 0x008001b8.0181.26 ---- 1 fsc 0x0000.00000000
0x03 0x0003.02a.000001ef 0x00800276.0167.09 ---- 1 fsc 0x0000.00000000
0x04 0x0008.023.00000434 0x00800348.01d4.34 ---- 1 fsc 0x0000.00000000
0x05 0x0001.027.00000372 0x00800763.01bb.30 ---- 1 fsc 0x0000.00000000
0x06 0x0002.00e.00000419 0x008003d3.016d.13 ---- 1 fsc 0x0000.00000000

この255の固定値を変えることはできないでしょうか。次のようにTAB$テーブルを直接修正するによってもっと低い値に変えることができます。すなわち次のように作業を修行すればMAXTRANSの値が255ではなくて5で低くなります。

SYS@ukja1021> connect sys/oracle as sysdba
Connected.

SYS@ukja1021> col object_id new_value v_obj_id
SYS@ukja1021> col data_object_id new_value v_data_obj_id
SYS@ukja1021>
SYS@ukja1021> select object_id, data_object_id from all_objects
2 where object_name = 'T1';

OBJECT_ID DATA_OBJECT_ID
---------- --------------
54298 54298

Elapsed: 00:00:00.07
SYS@ukja1021>
SYS@ukja1021> alter system flush shared_pool;

System altered.

Elapsed: 00:00:00.07
SYS@ukja1021> alter system flush shared_pool;

System altered.

Elapsed: 00:00:00.00
SYS@ukja1021>
SYS@ukja1021> update tab$
2 set maxtrans = 5
3 where obj# = &v_obj_id and dataobj# = &v_data_obj_id
4 ;
old 3: where obj# = &v_obj_id and dataobj# = &v_data_obj_id
new 3: where obj# = 54298 and dataobj# = 54298

1 row updated.

Elapsed: 00:00:00.03
SYS@ukja1021>
SYS@ukja1021> commit;

Commit complete.

Elapsed: 00:00:00.00
SYS@ukja1021>
SYS@ukja1021> alter system flush shared_pool;

System altered.

Elapsed: 00:00:00.00
SYS@ukja1021> alter system flush shared_pool;

System altered.

Elapsed: 00:00:00.00

5で変えたMAXTRANSの設定値がちゃんと動作するのかテストしてみます。次のように同時に7個のトランザクションを作ります。いままで6個のITLエントリをもう作ったので万一5の値が動作するといえば7番目のトランザクションはITLエントリ待機(enq: TX - allocate ITL entry)状態になるはずです。

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 1

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 2

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 3

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 4

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 5

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 6

UKJA@ukja1021> ho start sqlplus ukja/ukja@ukja1021 @temp 7

UKJA@ukja1021> @wait
UKJA@ukja1021> set echo off

SID EVENT P1 P2 P3
---------- ------------------------- --------------- --------------- ----------
SECONDS_IN_WAIT
---------------
136 enq: TX - allocate ITL en 1415053316(5458 524332(0008002C 1075(00000
try 0004) ) 433)
0

Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0008.02c.00000433 0x00800349.01d4.01 ---- 1 fsc 0x0000.00000000
0x02 0x0002.01d.00000419 0x008003c0.016d.17 ---- 1 fsc 0x0000.00000000
0x03 0x0007.00f.0000036f 0x00800609.0217.0c ---- 1 fsc 0x0000.00000000
0x04 0x0004.010.00000370 0x008001b8.0181.27 ---- 1 fsc 0x0000.00000000
0x05 0x0005.027.000004d6 0x0080095b.01ca.1e ---- 1 fsc 0x0000.00000000
0x06 0x0001.00b.00000372 0x00800764.01bb.01 ---- 1 fsc 0x0000.00000000

ITLが6個からその以上大きくならず7番目のトランザクションはITLエントリ待機状態になったのが分かります。


「MAXTRANSを低くする必要がなるほどいるのか」という疑問を持っている方なら次のブログポストをご覧ください。

No comments:

Post a Comment