Block Dump

目次

Block Dump

トランザクションでの状況を理解するには、トランザクション発生時いくつかの段階でどのようなデータがどのような形で変更されるかを理解する必要があります。特に、データブロックと、UNDO領域でのデータの変更についての理解が必要となります。オラクルが提供するダンプ(Dump)機能を利用すれば、トランザクションによって変更されたデータ情報を物理的に観察することができます。一つの簡単な例を使用して、これを議論してみましょう。

プロセスAがtestという名前のテーブルの特定の行を次のように変更することを例にとります。

SQL> update test set id = 1 where rownum = 1;

Updateが行われた行の位置をDBMS_ROWIDパッケージを利用して取得します。

SQL> 
select rowid, dbms_rowid.rowid_relative_fno(rowid) as fno,
      dbms_rowid.rowid_block_number(rowid) as blkno
from test where rownum = 1;
ROWID                     FNO      BLKNO
------------------ ---------- ----------
AAAMZqAABAAANoKAAA          1      55818

 

変更された行が配置されたブロックアドレスは、ファイル番号が1番、ブロック番号が55818番に該当します。この値を利用して、そのデータブロックを次のようにダンプすることができます。

SQL> alter system dump datafile 1 block 55818

 

Start dump data blocks tsn: 0 file#: 1 minblk 55818 maxblk 55818 
buffer tsn: 0  rdba: 0x0040da0a (1/55818)
scn: 0x0000.02ec5e30 seq: 0x02 flg: 0x02 tail: 0x5e300602
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump:  0x0040da0a
 Object id on Block? Y
 seg/obj: 0xc66a  csc: 0x00.2ec5e34  itc: 2  flg: -  typ: 1 - DATA
     fsl: 0  fnx: 0x0 ver: 0x01
 
Itl	Xid                  	Uba			Flag Lck        Scn/Fsc
0x01	0x0016.026.00003222	0x01c0003f.0410.26	----	1	fsc …
0x02	0x0016.025.00003222	0x01c0003f.0410.25	C---	0	scn …
 	? ITL 정보
data_block_dump,data header at 0x862025c
===============
tsiz: 0x1fa0
hsiz: 0x20
pbl: 0x0862025c
bdba: 0x0040da0a
     76543210
flag=--------
ntab=1
nrow=7
...
block_row_dump:	? Row 데이터 정보
tab 0, row 0, @0x13cd
tl: 1009 fb: --H-FL-- lb: 0x1  cc: 2    ? 로우에 Lock Byte 정보가 있음
col  0: [ 2]  c1 02
col  1: [1000]
 31 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
 ...
tab 0, row 1, @0xfdc
tl: 1009 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 03
col  1: [1000]
 31 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
...

 

ブロックダンプファイルの内容から、次のような事実を確認することができます。

 

(1)ITL(Interested Transaction List)に、行を変更したトランザクションがitl=0x01として登録されています。現在の状態は、まだコミットされていないアクティブ(Active)状態であり、したがってTXロックを獲得しています。Xid=0x0016.026.00003222ですが、この値を10進数に変換すると、USN=22、SLOT=38、SQN=12384となります。V$ TRANSACTIONビューで、現在のセッションに対応する情報を確認してみると、完全に一致することが確認できます。

SQL> select xidusn,xidslot,xidsqn from v$transaction 
         where addr = (select taddr from v$session where sid  = 162);
   XIDUSN    XIDSLOT     XIDSQN
---------- ---------- ----------
       22         38      12834        XID = USN + SLOT + SQN

 

(2)ITL情報ではLock=1ですが、これはTransactionによって変更されたローの数を意味します。また、まだコミットが実行されていないのでFlagには何の値も設定されていません。同じ理由でSCNもまだ割り当てられていません。Flagの値が「C」または「U」である場合には、コミットが行われたことを意味します。

 

(3)ITL情報のUBA(Undo Block Address)情報を利用して、現在のトランザクションが直近に使用した、UNDOブロックとUNDOレコードの位置を把握することができます。UBAは[UNDOブロックDBA+ Seq#+ Record#]になます。ロールバックを実行する場合は、この情報を利用します。

 

4)block_row_dump領域での最初の行のlb値は0x1に設定されています。lbはLock Byteの略で、現在の行にロックをかけたITL番号をさします。1回ITLが現在行を変更したことを意味します。Lock byteの値は、実際にコミットが発生してもまとめ(Cleanout)られず、後でDelayed block cleanoutが発生したり、他のプロセスによってブロックが変更したりしたに場合にまとめられます。

一つ注意することは、最初の行を変更した1番のトランザクション(ITLに登録された)でコミットが行われたか否かは、実際には、UNDOセグメントヘッダのトランザクションテーブルを照会することで知ることができるということです。 Oracleは、コミットが行われた時、トランザクションによって変更されたすべてのデータブロックのITLについていちいちコミット処理をしていません。変更されたブロックのうち、現在のバッファキャッシュに上がってきているものの中で一部だけをコミット処理し、残りのブロックには、トランザクションに割り当てられた、UNDOセグメントヘッダのトランザクションテーブルスロットのみコミット処理を行います。このデータブロックは、後で別のセッションでスキャンされるとき、実際のCleanout処理がなされます。これらのメカニズムをdelayed block cleanoutと呼びます。したがって、現在、特定の行が別のトランザクションによって変更していることかどうかを完全に把握するには、ITL情報だけでなく、場合によっては、UNDO情報まで照会しなければなりません。 一時、オラクルの最大の利点の一つとして、低レベルロック(Row level lock)を挙げたことがあります。オラクルのRow level lockは、明示的に存在しているロックではなく、上記の情報が組み合わされて実装されている論理的なロックです。Oracleは、個々の行を誰が変更しているかのリストやメタ情報を個別に管理してはいません。行がが変更されたか否かの情報は、その行を直接アクセスした場合だけ知ることができます。Row level locが物理的に存在しないことを理解しなければなりません。Row level locは、[行の変更かどうか+行を変更したトランザクション情報(ITL)+UNDO領域のトランザクションテーブルスロット+ TXロック]の情報が組み合わされた一種の論理的なロックなのです。Row level locはかなり明確でありながら混乱される概念がありますが、これはほとんどの文書でTXロックをRow level locと表現しているからです。さらに、Oracleのマニュアルでもあいまいな表現で説明されています。Row level locは、TXロックを利用して実装されます。TXロック自体がRow level locではなく、様々な情報が組み合わされて、Row level locが実装されているのです。