DFS lock handle

基本情報

 

DFS lock handleは要求されたGlobal lockのlock handleを待っている待機イベントです。このlock handleはglobal lockと同じです。 lock handleを取得するとglobal lockを所有した状態でlock conversionやlock releaseなどの複数のタスクを実行することができます。 global lockはDLMによって管理されます。

 

DFSはDistributed File Systemの略で、Oracle製品の歴史と関連している用語であると考えられます。Oracle 10g RACの機能が完成されるまで、Oracleはかなりの期間の間に分散データベースを実装しており、最初の分散データベースは、分散ファイルシステムをベースにしていたことが知られています。このような理由から、これまでいくつかのglobal lock競合ではまだDFSという用語を使用しています。

 

ほとんどのlockのグローバル競合は、シングルインスタンス環境で発生するような待機イベント名に観察されます。例えば、グローバルTM lock競合はenq:TM – contentionイベントで観察され、グローバルSQ lock競合はenq:SQ – contentionイベントに観察されます。これらとは異なり、DFS lock handle待機イベントで観察されている代表的なglobal lock競合はSV lock競合とCI lock競合があります。

 

パラメータと待機時間

 

待機パラメータ

 

DFS lock handle待機イベントのパラメータ情報は、enqueue待機イベントと同一です。

P1:lockタイプと要求(requested)モードを示します。lockタイプはTX、TM、SQ、SV、CIなどのlockタイプを意味します。
  モードは1(N)〜6(X)のlockモードを意味します。この値は、ASCII形式でエンコードされているので、次ののSQLを
  使用してenqueue名要求モードを確認することができます。

SELECT chr(to_char(bitand(p1、-16777216))/16777215)||
chr(to_char(bitand(p1、16711680))/65535)「Lock」、
to_char(bitand(p1、65535))"Mode"
FROM v$ session_wait
WHERE event="DFS lock handle」

  (32 -  bitオラクルの実行結果)
    SID EVENT P1 P1RAW Lock Mode
----------------------------------------------------------------------
     24 enqueue141505331854580006 TX6

  (64 -  bitオラクルの実行結果)
    SID EVENT P1 P1RAW Lock Mode
--------------------------------------------------------------------
    132 enqueue14150533180000000054580006 TX6

64-bitの場合は、上記の0を無視し、最後4byte、(32bitは4byteで構成されている)で、上位2byteはlockタイプです。
54580006の場合、上位2byteは0x5458HEXある。54は10進数で84であり、58は88であるため、
lockタイプは以下のように調べることができます。

Select chr(84) || chr(88) from dual;
CH
--
TX

lockモードは、残りの2byteにエンコードされているが、簡単に知ることができます。
上記の例では、lockモードは0x0006HEXのですので6となります。
Lockモードは、次のとおりです。

Mode Value	Description
 1	     Null Mode
 2	     Sub-Shared
 3	     Sub-Exclusive
 4	     Shared
 5	     Share/Sub-Exclusive
 6	     Exclusive



P2:ID1。V$ LOCK.ID1カラムのような意味です。
P3:ID2。V$ LOCK.ID2カラムのような意味です。

 

待機時間

 

セッションがDLMからlock handleを所有するまでloopをすることで待機します。loopごとに0.5秒ずつ待機します。

 

Check Point&Solution

 

SequenceのCache Sizeの増加について

 

DFS lock handleイベントはOPSやRAC環境では、バッファキャッシュの同期を除くrow cacheやlibrary cacheの同期のためにlockを獲得する過程で待機するイベントです。複数のノード間でのシーケンスの順序を保証するには、グローバルにlockを獲得しなければならないため、この過程でDFS lock handle待機が発生するようになります。SV lockを獲得する過程で発生するDFS lock handle待機イベントのP1、P2の値はenq:SQ – contention待機イベントと同じです。(P1= mode+ namespace、P2= object#)したがってP1の値からSV lockかどうかを確認することができ、P2の値を使用して任意のシーケンスに対して待機が発生していることを確認することができます。SV lock競合の問題が発生した場合の解決策は、SQ lockの場合と同様です。キャッシュサイズを適切に増加するのが唯一の解決策です。

RACの場合SequenceにCACHE+ NOORDER属性の付与

 

  RACのようなマルチノード環境では、シーケンスのキャッシュサイズがパフォーマンスに与える影響は、シングルノード環境よりもはるかに大きくなります。したがって、可能であれば、CACHE+ NOORDER属性を付与して、十分な大きさのキャッシュサイズを付与することが望ましいことになります。もし順序を保証することが、必要であればCACHE+ ORDER属性を付与します。しかし、この場合、順序を保証するために、インスタンス間でデータ交換が絶えず発生します。これにより、NOORODER属性を付与した場合よりも性能面で不利となります。

Event Tip

 

Sequence属性に応じた待機イベント

 

一つ注意することはCACHE属性を付与していない場合には、ORDER属性を使用するかどうか、またはRAC環境かどうかとは無関係に、常にrow cache lockイベントを待機するということです。 Row cache lockは、グローバルに使用可能なlockであり、シングルインスタンス環境やマルチインスタンス環境で同じように使用されます。シーケンスの作成時に付与された属性に応じた待機イベントを整理すると、次の通りです。

 

・row cache lock:Sequnece.nextvalを呼び出す過程でディクショナリ情報を物理的に変更する場合に獲得します。
          NOCACHE属性を付与したシーケンスで使用されます。
・SQ lock:メモリにキャッシュされている範囲内でSequence.nextvalを呼び出し中に獲得します。 
      CACHE属性を付与したシーケンスで使用されます。
・SV lock:RACでノード間の順序が保証された状態でSequence.nextvalを呼び出し中に獲得します。 
      CACHE + ORDER属性を付与したシーケンスで使用されます。

row cache lock競合

 

キャッシュ(Cache)属性を付与していないシーケンスを同時に多くのプロセスが使用している場合、row cache lockイベント待ちが広く発生することがあります。キャッシュを使用していないシーケンスのnextvalを呼び出すと、毎回Dictionary情報が変更されるべきであるためrow cache lockをSSXモードで獲得しなければなりません。SSXモード間の相互互換性がないため、この過程で競合が発生することにります。Row cacheダンプとV$ ROWCACHE_PARENTビューから正確なオブジェクトの情報を確認する方法を使用してrow cache lockの情報を調べてみましょう。

 

SQL> create sequence seq_seq nocache; -  NOCACHE属性のシーケンスを生成します。
 - シーケンスのObject IDを取得し、これを16進数に変換します。16進数に変換された値を用いなければならない
  row cacheダンプ内のシーケンスの情報を参照することができます。

SQL> select object_id from DBA_OBJECTS where object_name= 'SEQ_SEQ';
 OBJECT_ID
 ----------
    107886

SQL> select to_hex(107886)from dual;
TO_HEX(107886)
------------------------------------------
1A56E alter session set events」immediate trace name row_cache level12 '

 

 -  Row Cacheダンプファイルの内容は、次のとおりである。
------------(ダンプファイル開始)----------------------------------------------
....
BUCKET104:
  row cache parent object:address=201D46CC cid=13(dc_sequences)
  hash= ba7abee7 typ=9 transaction=00000000 flags=00000002
  own=201D4740【201D4740,201D4740] wat=201D4748【201D4748,201D4748] mode= N
  status= VALID/ - / - / - / - / - / - / - / - 
  data=
  0001a56e00020004000f000200020001000002c1000000000000000000000000
  02c100000000000000000000000000000000000064640ace6464646464646464
  006464640080000000000000000000000000000000000000000002c100000000
  00000000000000002d2d00002d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d
  2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d

----------(ダンプファイル終了)--------------------------------------------------


上記のダンプファイルから意味のある情報は、以下の通りでです。

・Bucket:row cacheまた、一般的な他のオブジェクトのようにハッシュ値によるバケット構造で管理されることを
      知ることができます。
・address:Row Cache objectのメモリアドレス。V$ ROWCACHE_PARENTビューと結合することができます。
・cid:Category id。V$ ROWCACHE.CACHE#と結合することができます。
・own:row cache lockを保有しているプロセスのリスト
・wat:row cache lockを待機しているプロセスのリスト
・mode:現在row cache lock保有モード(N= Null)
・data:最初の16進数が1a56eでSEQ_SEQのobject_idの16進数の値と同一であることを知ることができます。

 

次に、nextvalを大量に呼び出しながらrow cache lockがどのように獲得されるかを観察してみましょう。 以下のように10000回の間seq_seq.nextvalを呼び出します。

 

row cache lockを獲得してオフにする時間は非常に短いので、多くの回数を実行することで観察が可能となります。

SQL> declare
SQL>   v_seq number;
SQL> begin
SQL>   for idx in 1 .. 10000 loop
SQL>     select seq_seq.nextval into v_seq from dual;
SQL>   end loop;
SQL> end;
SQL> /

上記のPL/SQLが実行される間、ダンプを使用して得られたaddress=201D46CC値を利用して、V$ROWCACHE_PARENTビュー情報を照会すると、
以下の結果のようにSSX(Shared Sub-Exclusive)モードでrow cache lockを獲得することを知ることができます。

SQL> select * from v$rowcache_parent where address='201D46CC';

INDX                    : 2237
HASH                    : 103
ADDRESS                 : 201D46CC
CACHE#                  : 13
CACHE_NAME              : dc_sequences
EXISTENT                : Y
LOCK_MODE               : 5

 

Shared Sub-Exclusiveモードの意味は、オブジェクト全体には、Sharedモードで、オブジェクトの一部には、Exclusiveモードでロックを獲得することです。 Seqneuce.nextval呼び出しによってシーケンスディクショナリ情報が変更されている場合には、シーケンス自体を変更させるのではなく、シーケンスの「次の値」だけを変更させるので、SSXモードでrow cache lockを獲得するものです。

シーケンスを除いては、row cacheの情報をこのように頻繁に変更することはほとんどありません。したがってrow cache lock待機が表示される場合、シーケンスにNOCACHE属性が付与されていないか確認する必要があります。 OPS環境でのシーケンスの順序を完全に保証するためにNOCACHE属性にシーケンスを作成した場合にrow cache lock待機現象が表示される場合が多くあります。 RAC環境では、CACHE属性を使用しつつ、同時にノード間のシーケンスの順序を完全に保証することが可能です。

SQ Lock競合

 

CACHE属性が付与されたシーケンスのnextvalを呼び出し中に、SQ lockをSSXモードで獲得しなければなりません。同時に多くのセッションがSQ lockを獲得するために競争する過程で競合が発生した場合enq:SQ – contentionイベントを待機することになります。 enq:SQ – contentionイベントのP2の値は、シーケンスのオブジェクトIDです。したがってP2の値を利用してDBA_OBJECTSビューと結合する任意のシーケンスに対して待機現象が発生していることがわかります。

シーケンスの作成時に付与されたキャッシュサイズが小さい場合にenq:SQ – contention待機が増加する傾向があります。キャッシュサイズが小さい場合には、メモリにあらかじめキャッシュされた値が急速に排出され、キャッシュの値が排出された場合には、ディクショナリ情報を物理的に変更して再キャッシュする作業をしなければなりません。その中でSQ lockを継続して取得する必要があるため、enq:SQ – contentionイベントの待機時間がそれだけ増加します。 SQ lock競合によるパフォーマンスの問題は、CACHE属性を大きくすることで問題を解決することができます。残念ながら、シーケンスの作成時にキャッシュ・サイズのデフォルト値が20で小さく設定されています。したがって使用量が多いと予想されるシーケンスを生成する際にCACHE値を1000以上の大きな値で確保することが望ましいのです。。

たまに一度に多くのセッションが同時に生成されるときにenq:SQ – contention待機イベントが発生する場合があります。その理由は、V $ SESSION.AUDSID(Auditing session id)列の値がシーケンスを利用して生成されることから発生します。 Oracleは、新しいセッションが作成されるとSYS.AUDSES $という名前のシーケンスのnextvalを利用してAUDSID値を生成します。 SYS.AUDSES $シーケンスのキャッシュ・サイズは、デフォルトで20に設定されています。一度に多くのセッションが同時に接続する場合には、SYS.AUDSES $シーケンスのキャッシュ・サイズを10000程度大きく増やすことで、enq:SQ – contention待機問題を解決することができます。

RACでは、シーケンスの作成時にCACHE属性を付与した状態で、ORDER属性を付与しないと、各ノードが他の範囲のシーケンス値をメモリにキャッシュします。たとえば、2つのノードからなるRAC環境でCACHE 100属性にシーケンスを生成する場合、1回のノードは、1〜100回を使用して、2回のノードは、101〜200回を使用することになります。もし両ノード間の両方順次増加シーケンスを使用するには、以下のようにORDER属性を付与しなければなりません。

 

SQL> create sequence ordered_sequence cache 100 order;

SV Lock競合

 

SV lockはSequence Value lockの略でRACでORDER属性のシーケンス値を保護するために使用されるlockです。

CACHE + NOORDER属性のシーケンスが性能面では、最も有利です。しかし、NOORDER属性のシーケンスは、RACシステム内のノード間の順序を保証することができないという欠点があります。例えば、キャッシュサイズが100であり、NOORDER属性が付与されたシーケンスを2ノードで構成されるRACシステムで使用すると、ノード1に1〜100番、ノード2に101〜200回のシーケンスのキャッシュを使用することになります。したがって、クライアントがRACシステムに接続して、そのシーケンスを使用すると、シーケンスの値が「1、2、101、3、102、103 “のように、両方のノードのキャッシュ値が混在して抽出されます。ほとんどの状況では、このような現象が問題はありませんが、もしシーケンス値が必ず順次抽出する必要がある制約が必要な場合はORDER属性を付与することにより、このような現象を解消することができます。 ORDER属性のシーケンスでは、RACのすべてのノードが同じキャッシュ値を保持します。つまり、ノード1も1〜100番、ノード2も1〜100回のシーケンスのキャッシュを使用して、両方のノードは、SV lockを利用して、グローバルシーケンスの同期を実行します。

ORDER属性を使用する場合、シーケンスの値を抽出するたびにSV lockのグローバル同期処理が発生するのでNOORDER属性を使用するよりも性能面ではかなり不利です。しかし、NOCACHE属性を付与するよりもはるかに性能面では有利です。したがってRACシステムでは、可能な場合、CACHE + NOORDERプロパティを使用して、順序の保証が必要な場合に限りORDER属性を付与するのが得策です。 NOCACHE属性は、可能な限り使用してはなりません。

シーケンスキーの値が見つからない(Miss)場合、常に連続して増加しなければならないという前提条件のためにNOCACHE属性のシーケンスを使用している場合がしばしばあります。これはまず、性能面で非常に不利な選択となります。特にRACのような分散データベース環境では、NOCACHE属性のシーケンスが及ぼす悪影響は致命的なことになります。注意点としては、シーケンス値の欠落は絶対避けられないものであることです。 NOCACHE属性を付与しても、シーケンス値の欠落は常に発生します。例えば50万件のデータのキー値をシーケンスを利用して生成している途中にファイルスペースの不足によりロールバックが発生した場合は、この50万のシーケンスキー値は、不足している状態になります。このような理由から、NOCACHE属性のシーケンスは絶対に使用しないことを原則とすることを推奨します。

CACHE + ORDER属性が付与されたシーケンスである場合には、OracleはSQ lockではなく、SV lockを使用して同期を実行します。つまり、Order属性が付与されたSequenceに対してnextvalを呼び出すと、SSXモードでSV lockを獲得しなければなりません。 SV lockを獲得する過程で競合が発生した場合には、row cache lockイベントやenq:SQ – contentionイベントとは全く異なるDFS lock handleという名前のイベントを待機することになります。このような理由から、V $ EVENT_NAMEビューには、 “enq:SV – contention”のような名前のイベントが存在しません。