Enq: UL – contention

目次

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ロックを獲得する場合は、獲得するまで待機します。