Block Dump

EXEM Knowledge Base

Jump to: navigation, 찾기

트랜잭션에서의 대기현상에 대해 이해하려면, 트랜잭션 발생시 어떤 단계에서 어떤 데이터들이 어떤 형태로 변경되는지 이해할 필요가 있는데 특히 데이터 블록과 언두 영역에서의 데이터 변경에 대한 이해가 반드시 필요하다. 오라클에서 제공하는 덤프(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
...

블록 덤프 파일의 내용을 통해 다음과 같은 사실을 확인할 수 있다.

ITL(Interested Transaction List)에 로우를 변경한 트랜잭션이 itl=0x01로 등록되어있다. 현재 상태는 아직 커밋되지 않은 액티브(Active) 상태이며, 따라서 TX 락을 획득하고 있다. Xid = 0x0016.026.00003222 인데 이 값을 십진수로 변환하면 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)정보를 이용해 현재 트랜잭션이 가장 최근에 사용한 언두 블록과 언두레코드의 위치를 파악할 수 있다. UBA는 [언두 블록 DBA + Seq# + Record#]으로 이루어진다. 롤백을 수행할 경우 이 정보들을 이용한다.

4) block_row_dump 영역에서 첫번째 로우의 lb값은 0x1로 세팅되어 있다. lb는 Lock Byte의 약자로, 현재 로우에 대해 락을 건 ITL 번호를 말한다. 1번 ITL이 현재 로우를 변경했음을 의미한다. Lock byte의 값은 실제로 커밋이 발생해도 정리(Cleanout)되지 않으며, 나중에 Delayed block cleanout이 발생하거나 다른 프로세스에 의해 블록이 변경되는 경우에 정리된다. 한가지 주의할 것은 첫번째 로우를 변경한 1번 트랜잭션(ITL에 등록된)에서 커밋이 이루어졌는지 아닌지의 여부는 실제로는 언두 세그먼트 헤더의 트랜잭션 테이블을 조회해보아야 알 수 있다는 것이다. 오라클은 커밋이 이루어졌을 때, 트랜잭션에 의해 변경된 모든 데이터 블록의 ITL에 대해 일일이 커밋 처리를 하지 않는다. 변경된 블록 중 현재 버퍼 캐시에 올라와 있는 것들 중 일부만을 커밋 처리하며, 나머지 블록들에 대해서는 트랜잭션에 할당된 언두 세그먼트 헤더의 트랜잭션 테이블 슬롯에만 커밋 처리를 한다. 이 데이터 블록들은 나중에 다른 세션에 의해 스캔될 때, 실제 Cleanout 처리된다. 이러한 메커니즘을 delayed block cleanout 이라고 부른다. 따라서 현재 특정 로우가 다른 트랜잭션에 의해 변경 중인지의 여부를 완벽하게 파악하려면 ITL 정보뿐만 아니라 때로는 언두 정보까지 같이 조회해야 한다. 한때, 오라클의 최대 장점 중 하나로 로우 레벨 락(Row level lock)을 꼽았던 적이 있다. 오라클의 로우 레벨 락은 명시적으로 존재하는 락이 아니라 위의 정보들이 조합되어 구현되는 논리적인 락이다. 오라클은 개개의 로우를 누가 변경중인지에 대한 목록이나 메타정보를 별도로 관리하지 않는다. 로우가 변경되었는가의 정보는 해당 로우를 직접 방문해보아야만 알 수 있다. 로우 레벨 락이 물리적으로 존재하지 않는다는 것을 이해해야 한다. 로우 레벨 락은 해당 [로우의 변경여부 + 로우를 변경한 트랜잭션정보(ITL) + 언두영역의 트랜잭션 테이블 슬롯 + TX 락]의 정보들이 조합된 일종의 논리적인 락이다. 로우 레벨 락은 상당히 명확하면서도 혼란스러운 개념인데, 이는 대부분의 문서에서 TX 락을 로우 레벨 락이라고 표현하고 있기 때문이다. 심지어 오라클 매뉴얼에서도 애매모호한 표현으로 설명되어 있다. 로우 레벨 락은 TX 락을 이용해 구현되지만 TX 락 자체가 로우 레벨 락은 아니며, 다양한 정보들이 조합되어 로우 레벨 락이 구현된다.