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