트랜잭션(Transaction)에서의 대기이벤트들
enq:TM - contention
DML -> 관련 객체에 대한 변경 방지 위해 해당 테이블에 대해 TM 락 획득 -> 경합시 enq: TM - contention
- DML 락 : Data lock, DML 수행시 데이터를 보호하기 위한 락. 로우 락(TX)은 특정 로우를 보호하고, 테이블 락(TM)은 전체 테이블을 보호한다. DBA_DML_LOCKS를 통해 관찰 가능하다.
- DDL 락 : Data dictionary lock. User/Table/View/Procedure 등의 정의를 보호한다. DBA_DDL_LOCKS를 통해 관찰가능하다.
두 락이 별개로 존재하는 것은 아니다 - DML락은 실제로 TM락과 일치한다//DDL락은 실제로는 library cache lock과 일치한다.
일반적인 DML문은 테이블에 대해 TM락을 SX모드로 획득 -> SX모드는 상호 호환성이 있기 때문에, 여러 세션이 동시에 한 테이블에 대해 DML하는 것이 가능하다. (로우에 대해서는 TX락을 exclusive하게 획득)
-> DML간에는 TM락을 둘러싼 경합이 발생하지 않는다 -> enq: TM - contention 대기 이벤트도 발생하지 않는다.
주로 TM Lock 경합이 발생하는 경우
- 인덱스가 없는 Foreign Key의 부모키를 변경하는 경우
- DML과 DDL 간의 TM 락 경합
- Lock table.. 에 의한 TM 락 경합
- Direct Load 작업에 의한 TM 락 경합


인덱스가 없는 Foreign Key
9i부터는 알고리즘이 개선되어 경합 거의 발생 안한다 -> 9i 이전의 이야기임
-> foreign key 컬럼에 인덱스가 없는 상태에서 부모 테이블의 key가 변경되면, 자식 테이블에 대해 Shared 모드나 SSX모드로 TM락을 획득 했었다 -> 부모Key 변경한 트랜잭션이 종료될때까지 유지.

부적절한 DDL로 인한 TM 락 경합
DDL이 수행중인 테이블에 대해서 DML을 수행하는 경우 - TM락 경합 발생할 수 있음
ex 인덱스 생성시 테이블에 TM락 Shared모드로 획득 -> 이때 DML하려면 TM락을 SX모드로 획득해야함 -> 호환안되는모드임 -> DML을 수행하는 세션은 DDL 끝날때까지 enq:TM - contention 대기 이벤트
DDL로 인한 TM락 경합 해소법
- 데이터량이 많은 테이블에 DDL을 수행하지 않아도 되게끔 원천적으로 방지한다.
- DDL 수행시 Online 옵션을 사용한다 -> 온라인 옵션 사용하면 TM락을 Shared모드가 아닌 SS모드로 획득한다 -> SS와 SX는 호환됨.
- Parallel DDL을 사용해 DDL이 발리 종료되도록한다. NOLOGGING도 좋다.

Lock table.. 을 이용해 의도적으로 TM 락을 획득하는 경우
의도적으로 TM락을 획득한 경우임 -> TM락 경합이 발생한다면 락홀더 쪽에서 수행한 SQL구문 확인하는것이 중요하다. 매우 다양한 원인이 존재하기 때문
구문을 확인했더니 lock tacle ~~ 구문이더라 -> 어플리케이션 수정하자 -> 테이블 전체에 락거는 것 말고 DBMS_LOCK패키지나 select ~~~ for update등의 대안이 있다.

Direct/Parallel Load 작업을 수행한 경우
/*+ APPEND */ 힌트 주거나, SQLLoader등에서 direct path load 사용했다 -> TM락을 Exclusive하게 획득한다. SGA를 거치지 않는 작업이므로, 안전을 위해 TM락 걸고 아무도 못바꾸게한다.
그동안 테이블에 DDL, DML불가하게된다. -> 작업 시작 전에 문제 발생하지 않을지 미리 확인한다. SQLLoader작업시 parallel모드라면 TM락 shared모드로 획득하니 이것도 고려하자.

 

enq:TX - row lock contention, enq:TX - allocate ITL Entry, enq:TX - index contention
10g 이전에는 TX락에 의한 모든 대기현상이 enqueue라는 하나의 대기 이벤트로 표현됐었음
TX락은 트랜잭션을 보호 -> 트랙잭션이 종료되어야 해제됨 -> 즉 TX락을 획득하려면, 락 보유 세션이 트랜잭션 마칠때까지 기다려야한다.
TX락 경합이 관찰되는 상황들

여러 세션이 동일 로우를 변경하는 경우(enq: TX - row lock contention, mode=6)
로우 레벨 락 구현법 = 로우 자체의 변경사실 + ITL + 트랜잭션 테이블 슬록 + TX락
특정 로우를 변경하려 했는데, 이미 변경된 상태라면 -> ITL에서 해당 로우를 변경한 트랜잭션 확인 -> 자신을 TX Enqueue 목록에 추가 -> enq: TX - row lock contention 대기 이벤트
동일 로우 변경에 따른 TX락 경합은 어플리케이션 이슈이다 -> 장시간 수행되는 update, delete는 트랜잭션이 적은 시간대에 수행 || 혹은 update delete등의 성능을 개선하도록 한다.
-> 대량의 업데이트를 대신하기 위해 : 아예 새로운 테이블을 만들어서 거기서 작업하고 이름을 바꾸는 방식이 있다.

여러 세션이 Unique Key 충돌을 일으키는 경우(enq: TX - row lock contention, mode=4)
unique key나 primary key 충돌 발생시도 TX 락 경합 발생. 먼저 TX락을 보유하고 있던 세션이 트랜잭션을 마칠때까지 기다렸다가, ORA-00001이 뜨게 되거나, 성공적으로 트랜잭션이 종료될 것이다.
그 중간 단계 동안에는 enq: TX - row lock contention 이벤트를 대기하고 있게 된다.
- 입력해도 되는 값인지를 조회해봐야겠는데, 이전 트랜잭션이 아직 살아있으니, 그 트랜잭션이 종료되기를 기다렸다가, 조회하게 된다. (자신만의 TX락을 exclusive하게 획득한 상태에서, 이전 세션이 갖고있는 TX락을 Shared하게 획득하려고 대기하는 것)
-> 시퀀스를 사용해서 Unique Key를 생성하는 방식이 최선의 해결책.

ITL 엔트리 부족(enq: TX - allocate ITL entry, mode=4)
모든 트랜잭션은 블록을 변경시키기 전에 블록 헤더의 ITL에 엔트리를 등록해야 한다 -> 헌데 ITL 공간이 부족하면, 현재 ITL에 엔트리 등록한 프로세스가 Exclusive하게 획득한 TX락을 Shared하게 획득하기 위해 enq: TX - allocate ITL entry 이벤트 대기
- ITL에 엔트리를 등록한 뒤에야 실제 트랜잭션 작업을 시작할 터인데, ITL 엔트리가 부족하기 때문에 ITL슬롯을 할당받기 위해 대기한다
(아직 자신만의 TX락을 획득하지 못한 상태에서, 이전 세션이 갖고있는 TX락을 shared하게 획득하기 위해 대기)
-> 이러한 현상은 일반적으로는 일어나지 않는데, row chainnig, row migration이 발생한 로우가 있다면 동시에 여러 블록의 ITL헤더에 접근해야하므로 발생할 수도 있다
-> INITRANS값을 높게 잡아주는 것이 일반적인 해결법


여러 세션이 비트맵 인덱스(Bitmap Index) 충돌을 일으키는 경우 (enq: TX - row lock contention, mode=4)
비트맵 인덱스는 '컬럼의 값 + start rowid + end rowid + bitmap값'의 형태 -> 즉, 하나의 리프 노드가 넓은 범위의 rowid를 관리한다 -> 따라서, 테이블의 로우가 변경될 때마다 비트맵 인덱스에 해당하는 컬럼값에 로우가 속한 리프노드의 비트맵을 매번 새로 계산해주어야한다. -> 여러 세션이 동시에 같은 리프노드에 대해 작업하게 된다면, 리프노드에 대하여 TX락 경합 발생할 수 있다.
-> DML이 빈번한 테이블에 비트맵을 쓰지 않도록 한다.

인덱스 리프 노드에서 Split이 발생하는 경우(enq: TX - index contention, mode=4)
비트리 인덱스 걸려있는 테이블에서 -> 데이터 추가(TX락을 exclusive하게 획득한 상태) -> 리프노드가 꽉 차서 split을 해야하는 상황이 온다 -> TX락을 exclusive하게 획득해 놓은 상태이므로, 다른 세션에서는 split 작업이 진행되고 있는동안 계속 기다려야한다.
쉽게 발생하지는 않는다 - 동시에 여러 세션이 인덱스 생성되어있는 테이블에 많은 양의 DML을 수행한다거나 할 경우 발생 -> 인덱스가 많고, 인덱스를 이루는 컬럼값이 커서 split도 자주일어난다면 이 문제가 크다.
-> 파티션을 사용하여 물리적을 분산시키거나, 인덱스 구성하는 컬럼의 순서를 변경하는 식의 해결법이 있다.
-> 인덱스의 블록 크기를 크게 설정한다거나(한 블록에 많이 집어넣을 수 있음 - split현상 줄이기),

기타 (enq: TX - contention)
이 외에 TX락을 필요로 하는 경우들
- 분산 트랜잭션 환경에서 Prepared Transaction에 의해 락이 획득된 로우를 읽는 경우, 트랜잭션이 종료(rollback, commit, in-doubt)될때까지 TX 락을 Shared 모드로 획득하기 위해 대기해야 한다.
- FLM을 세그먼트 공간 관리기법으로 사용하는 경우, TFL을 확보하려는 프로세스는 TFL을 확보하지 못할 경우 미이 TFL을 확보한 Transaction의 TX락을 Shared 모드로 확보하기 위해 대기해야 한다.
- 언두 세그먼트 헤더의 트랜잭션 테이블에서 새로운 슬롯을 할당받고자 하는 경우 TX 락을 Exclusive하게 획득해야 한다.

 

enq: UL - contention, PL/SQL lock Timer
DBMS_LOCK 패키지를 사용 - 물리적 자원이 아닌 가상적인 자원에 대해 락을 걸 수도 있다
DBMS_LOCK 패키지를 이용해 획득하는 락을 UL(User-defined Lock)락이라고 부른다. UL락 획득 위해 대기하는 이벤트가 enq: UL - contention이다.
-> DBMS_LOCK패키지를 제대로 못쓰면 이렇게 경합이 발생하게 될 것이다. 어플리케이션 구성할때 잘 검토해서 해야한다.

레이블 (0)

  • 레이블 없음
댓글 쓰기...

첨부 파일  (0)

첨부 파일 추가하기
공유된 파일이 아직 없습니다.