Enq: UL - contention

EXEM Knowledge Base

Jump to: navigation, 찾기

목차

[편집] Basic Info

DBMS_LOCK 패키지를 사용하면 사용자가 임의의 가상적인 자원에 대해 락을 걸 수 있다. DML에 의해 발생하는 락의 경우 반드시 물리적인 자원(테이블/트랜잭션/세그먼트 등)을 필요로 하지만, DBMS_LOCK 패키지를 사용할 경우에는 이런 제한이 없다. DBMS_LOCK 패키지를 이용해 획득하는 락을 UL(User-defined Lock) 락이라고 부른다. UL 락을 획득하기 위해 대기하는 세션은 enq: UL - contention 이벤트를 대기한다. DBMS_LOCK.REQUEST 함수를 이용하면 UL 락을 Exclusive하게 획득하고, DBMS_LOCK.RELEASE 함수를 이용하면 락을 해제한다. 아래 테스트 스크립트를 보자. 세션A:(SID=156)

SQL>  -- "1" 이라는 자원에 대해 락을 획득
declare
 v_no number;
begin
 v_no := dbms_lock.request(1);
end;
/

세션B:(SID=151)

SQL> -- 세션A에 의해 점유된 "1"이라는 자원에 대해 lock 획득을 시도
declare
 v_no number;
begin
 v_no := dbms_lock.request(1);
end;
/
---- Wait ------------------

위와 같이 세션B는 세션A에 의해 점유된 "1"이라는 자원에 대해 락을 획득하기 위해 대기하게 된다. 이 상태에서 V$LOCK 뷰를 관찰해보자. 세션C:

SQL> exec print_table('select * from v$lock where sid in (156,151)');
ADDR                          : C0000000AE0A7AA0
KADDR                        : C0000000AE0A7AC0
SID                             : 156
TYPE                           : UL
ID1                             : 1
ID2                             : 0
LMODE                         : 6    ? UL락을 Exclusive하게 획득 중
REQUEST                     : 0
CTIME                         : 157
BLOCK                         : 1
------------------------
ADDR                          : C0000000AE0A78D8
KADDR                        : C0000000AE0A78F8
SID                             : 151
TYPE                            : UL
ID1                             : 1
ID2                             : 0
LMODE                         : 0
REQUEST                     : 6    ? "1"이라는 자원(ID1=1)에 대해 UL 락을 Exclusive하게 획득하기 위해 대기
CTIME                          : 40
BLOCK                         : 0
-----------------

테스트 UL 락 경합

세션A(SID=156)는 UL 락을 "1"이라는 리소스(ID1=1)에 대해 Exclusive하게(lmode=6) 획득한 상태이며, 세션B(SID=151)는 "1"이라는 동일 자원에 대해 UL 락을 Exclusive하게 획득하기 위해 대기하고 있는 것을 확인할 수 있다. DBMS_LOCK.RELEASE 함수를 이용해 락을 해제하고 세션 B에서의 대기이벤트를 조회하면 아래와 같이 enq: UL - contention 대기현상이 목격된다.

SQL> @event;
EVENT                          TOTAL_WAITS TIME_WAITED
------------------------------ ----------- -----------
enq: UL - contention                329       96703
SQL*Net message from client    29       36019
log file sync                                  2           1
db file sequential read                   2           1
SQL*Net break/reset to client         2           0
SQL*Net message to client           30           0

UL 락에 의한 경합은 DBMS_LOCK 패키지를 효율적으로 사용하지 못할 때 발생한다. DBMS_LOCK 패키지는 매우 단순하면서도 유연하고 강력한 블로킹 방법을 제공하지만, 자칫 잘못 사용하면 치명적인 경합을 초래할 수도 있음을 명심해야 한다. UL 락의 해제는 기본적으로 락을 보유한 세션에서만 가능하다. 따라서 특정 세션이 UL 락을 장시간 보유함으로써 동시성 문제를 일으키고 있다면 세션을 강제로 종료시키는 것 외에는 대안이 없다. DBMS_LOCK.REQUEST 함수 사용시 가능하면 release_on_commit 옵션을 사용해서 불필요하게 락을 보유하지 않도록 하는 것이 좋다. 이 옵션을 사용하면 커밋이나 롤백이 발생하면 해당 트랜잭션이 보유하던 UL락을 자동으로 해제한다.

DBMS_LOCK 패키지와 관련된 또 하나의 대기이벤트가 있다. DBMS_LOCK.SLEEP 프로시저를 이용해 트랜잭션을 잠시 중단할 경우 해당 프로세스는 PL/SQL lock timer 이벤트를 대기한다.

SQL> exec dbms_lock.sleep(1);
... 1초 동안 대기...

SQL> @my_sess_event

EVENT                          TOTAL_WAITS TIME_WAITED
------------------------------ ----------- -----------
SQL*Net message from client      20         790
PL/SQL lock timer                         1          99
log file sync                                  1           1
SQL*Net message to client           21           0

PL/SQL lock timer 대기이벤트에 의한 성능 이슈는 없다. 만일 해당 대기가 기대이상으로 높게 나오면 어플리케이션 구현 로직에 문제가 없는지 검토해보아야 한다.

[편집] Parameter & Wait Time

[편집] Wait Parameters

  • P1 : Enqueue 정보
  • P2 : User Defined Lock Id
  • P3 : 0

[편집] Wait Time

enqueue 대기이벤트와 동일하다. 최대 3초까지 기다린다. 만일 UL 락을 획득하기 못하면 획득할 때까지 대기한다.

[편집] Check Point & Solution

[편집] Event Tip

[편집] Analysis Case