続 X$BH に関する検証 その6

<続 X$BH に関する検証 ~その6~>
ペンネーム ちょびひげ

前回までは「単一サーバ」で、UPDATEなどの各処理を行い、どのような処理
を行なった場合に、CRブロックが作成される状況を見てきた。CRブロックは
読取一貫性を保つ為に作成されるブロックである。つまり、アクセスするデ
ータのバージョン(SCN)が欲しいバージョンと異なる場合(SCNの番号が必
要なSCNより大きい)にCRブロックが作成される。

CRブロックを作成するにはUNDOブロックを使用して、ブロックのバージョンを
古くする必要がある。ここで使用するUNDOブロックを特定するには、ブロッ
ク内のトランザクション・エントリが必要となる。

トランザクション・エントリに関しては、今までにも<ロックに関する検証
>や<ロールバックセグメントに関する検証>などで部分的に触れてきたが、
今回はバッファのダンプを取得して簡単にトランザクション・エントリとロ
ックの関係を見ていく。次回、カレント・ブロックとUNDO情報を使用して、
CRブロックが作成される様子を見ていく。

とりあえずは、ロックのメカニズムをおさらいしたい。

今回の検証も前回と同様に以下環境で行う。

*************************************************************
◆環境
Linux 2.4.2-2
Oracle9i EE Release 9.2.0.1.0

◆テーブル構成

SQL> desc test
 Name      Type
 --------- ------------------
 ID1       NUMBER
 ID2       NUMBER
 TEXT      VARCHAR2(2000)

※ID1にINDEX(TEST_IDX)を付与

入っているデータは以下の3件

       ID1        ID2 TEXT
---------- ---------- --------------------
         1          1 insight
         2          2 insight
         3          3 insight

まず初めに、2行のUPDATEをおこなって、どのようにロックが取得されている
かを見てみる。

SQL> update test set id1=1 where id1>1;

2行が更新されました。


OBJECT_NAME          STATE     DBABLK BA      
-------------------- ----- ---------- --------
TEST                 xcur       70913 54D12000 ← セグメント・ヘッダ
TEST                 xcur       70914 54D0E000 ← データ・ブロック
TEST_IDX             xcur       96394 54D10000 ← インデックス
データが以下の様に更新されている
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       ID1        ID2 TEXT
---------- ---------- --------------------
         1          1 insight
         1          2 insight
         1          3 insight

◇バッファ・ダンプを出力する為に、以下のコマンドを実行

SQL> alter session set events 'immediate trace name buffers level 6';

では、ダンプを見てみよう。

各ブロックのバッファ・ダンプは以下の構成である。

【バッファ・ヘッダ部】

【ブロック・ヘッダ部】

【データ・ブロック部】

上記の各部分に関して簡単に説明していく。

【バッファ・ヘッダ部】
バッファ・ヘッダにはバッファ・アドレス(BA)が含まれており、これを元
にX$BH表のデータとの結び付けを行う。また、この部分にSCN番号をもってお
り、現在のブロックのバージョンを知ることができる。

バッファ・ヘッダに関しては<Oracle 9iに関する検証>で既に行っているの
で詳しくは紹介しない。

【ブロック・ヘッダ部】
以下は、バッファ・ダンプのブロック・ヘッダの一部分である。
*************************************************************
ブロック・ヘッダ(テーブル)

Block header dump:  0x00411502
 Object id on Block? Y
 seg/obj: 0x82d0  csc: 0x00.887cc20  itc: 2  flg: O  typ: 1 - DATA
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0008.028.00027e99  0x00800974.09bd.3b  C---    0  scn 0x0000.08877c26
0x02   0x0002.02d.000281f5  0x0080083b.08ee.28  ----    2  fsc 0x0000.00000000
↑                                                      ↑
Itlエントリ番号                                         ロックの行数

【Itl, Lck】
0x02 のトランザクション・エントリ(Itl)がロック(Lck)を2行取得して
いる様子が分かる。フラグ(Flag)がCのエントリを既にコミットされたこ
とを示している。トランザクション・エントリはロールバックの情報と結び
つく重要な情報であるが、これに関しては次回詳しく見ていく予定である。

今回は上記のトランザクション・エントリとブロック内の各レコードの関係
を見て頂きたい。Itlが0x02のトランザクションが、ロックを2行取得してい
るが、どうやってレコードと結び付けているのであろうか?この結び付けが
出来なければ行ロックを実現することは出来ない。

では、データ・ブロックの内容を見てみる事にする。

【データ・ブロック部】
*************************************************************
データ・ブロック(テーブル)

data_block_dump,data header at 0x54d5405c
===============
・
<<省略>>
・
0x16:pri[2]     offs=0x1f6d
block_row_dump:
                      ↓【注目!】
tab 0, row 0, @0x1f8f
tl: 17 fb: --H-FL-- lb: 0x0  cc: 3
col  0: [ 2]  c1 02                     ← ID1 = 1
col  1: [ 2]  c1 02                     ← ID2 = 1
col  2: [ 7]  69 6e 73 69 67 68 74      ← TEXT= insight

tab 0, row 1, @0x1f5c
tl: 17 fb: --H-FL-- lb: 0x2  cc: 3
col  0: [ 2]  c1 02   ↑【注目!】
col  1: [ 2]  c1 03                     ← ID2 = 2
col  2: [ 7]  69 6e 73 69 67 68 74

tab 0, row 2, @0x1f6d
tl: 17 fb: --H-FL-- lb: 0x2  cc: 3
col  0: [ 2]  c1 02   ↑【注目!】
col  1: [ 2]  c1 04                     ← ID2 = 3
col  2: [ 7]  69 6e 73 69 67 68 74
end_of_block_dump

上記のデータを見ていただくとロックが掛かっていない行のlbは0x0であるが
、ロックが掛かっている行には、lb に先程のItlエントリ番号(0x02)がは
いっているのが確認できる。

このように、行単位でロックを取得し、そのロックを保持しているトランザ
クションの特定を行う事が出来るわけである。

では、インデックスの方も簡単にみてみよう。

*************************************************************
ブロック・ヘッダ(インデックス)

Block header dump:  0x0041788a
 Object id on Block? Y
 seg/obj: 0x82cf  csc: 0x00.888c646  itc: 3  flg: -  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x02   0x0008.028.00027e99  0x00800974.09bd.3c  C---    0  scn 0x0000.08877c26
0x03   0x0002.02d.000281f5  0x0080083b.08ee.2a  ----    4  fsc 0x001c.00000000
                                                        ↑
                                                        ロックを4つ取得!

データ・ブロック(インデックス)

Leaf block dump
===============
・
<<省略>>
・
row#0[7996] flag: -----, lock: 0
col 0; len 2; (2):  c1 02                ← ID1 = 1
col 1; len 6; (6):  00 41 15 02 00 00    ← ROWID

row#1[7912] flag: -----, lock: 3         ← Itl 3 がロックを取得
col 0; len 2; (2):  c1 02                
col 1; len 6; (6):  00 41 15 02 00 01    

row#2[7924] flag: -----, lock: 3
col 0; len 2; (2):  c1 02                
col 1; len 6; (6):  00 41 15 02 00 02    

row#3[7984] flag: ---D-, lock: 3         ← 更新前情報には削除フラグ(D)
col 0; len 2; (2):  c1 03                ← ID1 = 2
col 1; len 6; (6):  00 41 15 02 00 01    

row#4[7972] flag: ---D-, lock: 3         ← 更新前情報には削除フラグ(D)
col 0; len 2; (2):  c1 04                ← ID1 = 3
col 1; len 6; (6):  00 41 15 02 00 02    
----- end of leaf block dump -----

インデックスには更新前の情報も格納されているので、計4つのロックを保持
している。各更新前のレコードがどの更新後のレコードに相当するかはROWID
から確認することが出来る。上記の例では “col 1” の “00 41 15 02 00 01”
がROWIDを示している。

今回はトランザクション・エントリとロックされた各レコードとの関係をみ
た。トランザクション・エントリがOracleの行ロックを可能にしている重要
な情報であることが分かる。次回はトランザクション・エントリとUNDO情報
との関係を見ていく。

以上、雨上がりの茅ヶ崎にて