ITL(Interested Transaction List)은 특정 블록을 변경하고자 하는 트랜잭션의 목록을 의미하며, 블록의 헤더에서 그 정보를 관리한다. 블록을 변경하고자 하는 모든 트랜잭션은 블록 헤더의 ITL의 엔트리 중 하나로 자신을 등록해야 한다. 만일 ITL이 약속된 최대치, 즉 MAXTRANS에 의해 지정된 값을 초과하거나 블록 내의 여유공간이 부족해서 엔트리를 등록하는 것이 불가능한 경우, 프로세스는 이미 ITL에 엔트리를 등록한 프로세스가 Exclusive하게 획득한 TX 락을 Shared 모드로 획득하기 위해 대기하게 된다. 이때의 대기현상은 enq: TX - allocate ITL entry 이벤트로 관찰된다. 테이블을 생성할 때 부여하는 세가지 속성값이 ITL에 영향을 준다.
- INITRANS : 블록 헤더마다 몇 개의 ITL 엔트리를 미리 확보할 지를 결정한다. 가령 INITRANS의 값을 10으로 주면 10개의 동시 트랜잭션을 위한 공간이 마련된다.
- MAXTRANS : 최대 몇개의 ITL 엔트리를 허용할지를 결정한다. 가령 MAXTRANS의 값을 50으로 주면 최대 50개까지의 동시 트랜잭션을 허용한다. MAXTRANS의 기본값은 255이며, 오라클 10g부터는 MAXTRANS는 255로 고정된다. 즉, MAXTRANS 값을 지정해도 오라클은 이 값을 무시하며 항상 255의 값을 사용한다.
- PCTFREE : 블록이 최초 생성될 때는 INITRANS에 지정된 값만큼 ITL 엔트리가 확보되었다가, 동시 트랜잭션이 증가하면 PCTFREE로 확보된 영역 내에서 MAXTRANS만큼 추가로 확장된다.
만일 동시 트랜잭션이 왕성할 것으로 예상되는 테이블이라면 INITRANS를 충분히 주는 것이 좋다. INITRANS를 충분히 주면 동적으로 공간을 확보하는 오버헤드가 줄어들며, ITL 엔트리 부족에 따른 TX 락 경합이 발생할 확률도 줄어든다. 오라클 10g부터는 MAXTRANS의 값이 255로 고정되므로 잘못된 MAXTRANS 값 지정으로 인해 성능 문제가 생길 소지가 사라졌다. PCTFREE 값을 비정상적으로 작게 설정하는 경우 ITL을 동적으로 확장할 여유공간이 부족해서 문제가 될 수도 있다. 오라클 9i에서 MAXTRANS 값을 임의로 작게 준 경우 TX 락 경합이 어떻게 발생되는지 살펴보자.(오라클 9i에서 테스트를 하는 이유는 오라클 10g에서는 MAXTRANS가 255로 고정되었기 때문이다)
SQL> -- maxtrans 값을 2 로 준다. 이 경우 세개 이상의 세션이 동시에 블록을 변경하지 못한다. create table tx_itl_test(id number) initrans 2 maxtrans 2; -- 총 5건의 데이터를 생성한다. insert into tx_itl_test values(1); ... insert into tx_itl_test values(5); -- dbms_rowid package를 이용해서 같은 블록안에 들어가 있는 로우를 확인한다. SQL> select id, dbms_rowid.rowid_block_number(rowid) from tx_itl_test; ID DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) ---------- ------------------------------------ 1 175362 2 175362 3 175363 4 175363 5 175363 id값이 3, 4, 5 인 로우들이 175363번 블록에 있으므로 이 세개의 로우에 대해 동시에 다른 세션들에서 업데이트를 시도한다. 세션A:(SID = 27) SQL> update tx_itl_test set id = 3 where id = 3; 1 row updated. 세션B:(SID = 10) SQL> update tx_itl_test set id = 4 where id = 4; 1 row upated. 세션C:(SID = 40) SQL> update tx_itl_test set id = 5 where id = 5; ..... Wait ................................................... 세번째 업데이트를 수행한 10번 세션이 대기상태에 빠진다. 이 상태에서 V$LOCK 뷰를 통해 TX 락 경합이 어떻게 발생하는지 확인해보자 SQL> exec print_table('select * from v$lock where type = TX'); ADDR : C00000001EBA58B0 KADDR : C00000001EBA5A28 SID : 10 TYPE : TX ID1 : 65548 ID2 : 58643 LMODE : 6 ? TX 락을 Exclusive하게 획득중 REQUEST : 0 CTIME : 33 BLOCK : 0 ----------------- ADDR : C00000001EB9DCE8 KADDR : C00000001EB9DE60 SID : 27 TYPE : TX ID1 : 131072 ID2 : 68746 LMODE : 6 ? TX 락을 Exclusive하게 획득중 REQUEST : 0 CTIME : 43 BLOCK : 1 ----------------- ADDR : C00000001F1EFEE0 KADDR : C00000001F1EFF00 SID : 40 TYPE : TX ID1 : 131072 ID2 : 68746 LMODE : 0 REQUEST : 4 <-- Shared 모드로 TX 락을 획득하기 위해 대기 CTIME : 14 BLOCK : 0
테스트) ITL 엔트리 부족에 의한 TX 락 경합
위의 테스트 결과를 분석하면 성공적으로 update를 수행한 27번 세션과 10번 세션은 자신의 트랜잭션에 해당하는 TX 락을 Exclusive하게 획득하는데 성공했음을 알 수 있다. 문제의 40번 세션은 최초에 Update를 수행한 27번 세션이 획득한 TX 락(ID1=131072, ID2=68746)을 Shared 모드(REQUEST=4)로 획득하기 위해 대기하고 있다. Unique Key 충돌에 의한 TX 락 경합과 ITL 엔트리 부족에 의한 TX 락 경합 사이에는 미묘한 차이점이 있다. Unique Key 충돌의 경우, 대기세션은 자신만의 TX 락을 Exclusive하게 획득한 상태에서 이전 세션이 획득한 TX 락을 Shared 모드로 획득하기 위해 대기한다. 반면 ITL 부족의 경우, 대기세션은 자신만의 TX 락을 획득하기 전에 이전 세션이 획득한 TX 락을 Shared 모드로 획득하기 위해서 대기한다. 이러한 차이는 블록을 변경하기 전에 먼저 ITL 엔트리를 등록해야 하는 데서 비롯된다. ITL 엔트리 부족에 따른 TX 락 경합 현상은 일반적인 상황에서는 잘 생기지 않는다. 동시에 수십 ~ 수백 개의 세션이 하나의 블록에 대해 서로 다른 로우를 변경하는 경우는 매우 드물기 때문이다. 다만, Row Chaining이나 Row Migration이 발생한 로우의 경우 하나의 로우를 업데이트할 때 여러 개의 블록에 대해 각각 ITL 엔트리를 할당해야 하므로 이로 인해 ITL엔트리 부족에 의한 TX 락 경합이 발생할 확률이 높아진다.
[편집]Parameter & Wait Time
[편집]Wait Parameters
- P1 : Enqueue 정보
- P2 : usn<<16 | slot
- P3 : sequence
[편집]Wait Time
enqueue 대기이벤트와 동일하다. 최대 3초까지 기다린다. 만일 TX 락을 획득하기 못하면 획득할 때까지 대기한다
[편집]Check Point & Solution
[편집]높은 INITTRANS 속성 부여
높은 INITRANS 값으로 테이블을 생성하는 것이 ITL 공간 부족에 따른 TX 락 경합 현상을 해결하는 일반적인 방법이다. 더욱 중요한 것은 잘못된 어플리케이션 설계로 불필요한 경합이 발생되는 것인지 판단하는 것이며, 잘못된 설계에 의한 것이라면 어플리케이션을 수정하는 것만이 유일한 해결책이다.
V$SEGMENT_STATISTICS 뷰를 이용하면 어떤 세그먼트에 대해서 ITL 부족에 의한 경합이 많이 발생하는지 확인할 수 있다. STATISTIC_NAME = 'ITL waits' 조건을 이용하면 어떤 세그먼트에 대해 ITL 부족 문제가 많이 발생했는지 알 수 있다.
댓글 없음:
댓글 쓰기