Row Cache Lock
目次[非表示]
基本情報
Oracleは、ディクショナリの情報をSGA内のRow Cache(あるいはdictionary cache)領域に保存しています。Row CacheはShared Pool領域に存在し、次のようなクエリで確認することができます。
ディクショナリの内容を変更しようとするプロセスは、それに対応するrow cache objectに対してrow cache lockを獲得しなければなりません。row cache lockはRow Cache領域を保護するロックです。Row CacheあるいはDictionary Cache領域は、Oracleのディクショナリ情報を保持する共有メモリ領域には、多くのプロセスが同時にディクショナリ情報を参照するか、変更するRow Cacheでの競合が発生するのです。V$ ROWCACHEビューを参照するとどのような種類のデータがRow Cache領域で管理されているかどうかを確認することができます。
Row Cache Object(以下RCO)は、個々のディクショナリオブジェクトを意味します。例えば一つのシーケンスAがあるとましょう。シーケンスAは、物理的にSYSTEM表領域のSYS.SEQ$テーブルに格納されています。ユーザーがシーケンスAを参照するとSYS.SEQ$テーブルからシーケンスAに対応するロー(Row)をbuffer cacheを経由してRow Cache領域に読み込み、この過程で、シーケンスAに対応するRCOが生成されます。
通常のテーブルの場合、ブロック単位でキャッシュ領域に読み込む一方、ディクショナリ情報は、ロー単位でキャッシュ領域に読み込むため、Row Cacheという名前が付けられました。 RCOを変更しようとするプロセスは、必ずrow cache lockを獲得しなければならないのです。例えばSEQUENCE.NEXTVALを呼び出す過程でディクショナリ情報を変更する必要が生じた場合のシーケンスについてrow cache lockをSRX(5)モードで獲得しなければなりません。 ALTERステートメントを利用して、テーブルを変更するプロセスは、テーブルのrow cache lockを排他的(X)モードで獲得しなければならないのです。
Row cache lockはEnqueue構造を使用せず、row cache object情報の中に存在するロック保持リスト(Owner list)とロック待ちリスト(Waiter list)を介してブロックメカニズムを実装します。このような構造は、library cache lock、library cache pin、buffer lockと同様なのですが、バッファヘッダーにuser listとwaiter listが存在し、この二つのリストを使用してブロッキングメカニズムを実装します。よくrow cache lockをrow cache enqueueと呼ぶのですが、これは意味を正確に伝達するために使用される用語であるだけでTXロックのようにEnqueue構造を使用しないという点に注意してください。
V $ ROWCACHEビューとV $ ROWCACHE_PARENTビューを使用すると、row cacheでの競合の分析が可能となります。 V $ ROWCACHEビューは、個々のrow cache objectではなく、row cache全体(種類)の活動性に関する統計情報を提供します。 V $ ROWCACHE_PARENTビューを使用すると、実際の個々のrow cache objectの活動性を把握することができます。 row cache lock待機イベントの一つ不便な点は、実際のオブジェクトの情報ではなく、オブジェクトの種類の情報だけを提供するものであることです。これにより、正確にどのようなrow cache objectが問題になるのかを把握するのは難しいことなのです。 row cacheダンプを使用すると、実際のオブジェクトに関する情報まで得ることができます。
待機パラメータと待機時間
待機パラメータ
RCOを使用するすべてのプロセスは、row cache lockを獲得しなければなりません。Row cache lockを獲得する過程で競合が発生した場合row cache lockイベントを待機します。row cache lock待機イベントのパラメータの定義は、以下の通りです。
待機時間
3秒間待機します。100回のタイムアウトが発生した場合、プロセスは中断され、alert logファイルに「WAITED TOO LONG FOR A ROW CACHE ENQUEUE LOCK」とエラーメッセージを記録した後、終了します。
チェックポイントと解決策
NOCACHE属性のシーケンスを使用している場合
Row cache lockの競合が最も頻繁に発生する場合は、NOCACHE属性のシーケンスです。キャッシュを使用していないシーケンスは、次の値(NEXTVAL)を呼び出すたびにディクショナリ情報を変更する必要があり、この過程でRCOについてrow cache lockをSRX(5)モードで獲得しなければなりません。SRXモード間での互換性がない。したがってNOCACHE属性のシーケンスに複数のセッションが同時に次の値(NEXTVAL)を呼び出す場合には、row cache lockイベントの待機が広範囲に発生し、P2の値は「5」で観察されるのです。次の例は、NOCACHE属性のシーケンスが使用されている環境で発生するrow cache lock待機現象を監視したものでP3(request)の値が「5」の値を示すことを確認することができます。
NOCACHE属性のシーケンスを使用することによってrow cache lockが発生した場合、複数のセッションで同時に使用されるシーケンスは、キャッシュのサイズを大きくしてくれることが望ましい事になります。1000程度のキャッシュサイズをデフォルトとして使用しますが、必要であれば、10,000以上の大きな値を付与してもよいのです。
同時実行性の高いシステムでは、常にrow cache lock競合が生じる危険性が常に存在します。シーケンスを除いた大部分のrow cache lock競合現象は明確なチューニング方法がないのが現状です。適切なシステムのチューニングを介して同時実行を減らすことが最善の方法となります。
Event Tip
待機イベントを通じたrow cache rockの確認
Row cache lockの競合を観察するための最も簡単な方法は、待機イベントを利用するものである。しかし、待機イベントだけではロックホルダーセッションと待機セッションの間の競合関係を把握するのが難しい。 V $ ROWCACHE_PARENTビューを利用すれば、これらの競合関係を把握することができる。まずV $ ROWCACHE_PARENTビューの重要な列の意味を調べてみよう。
次のスクリプトは、NOCACHE属性のシーケンスを使用で発生するrow cache lockの競合をV $ ROWCACHE_PARNETビューを介して観察する例である。
セッションアドレス値”C00000009E089540」に該当するセッションが5(SRX)番モードでrow cache lockを獲得しており、残りのセッションは5(SRX)番モードでrow cache lockを獲得するために待機しています。キャッシュの種類はすべてのシーケンス(dc_sequences)です。このように、V$ ROWCACHE_PARENTビューとV$ SESSIONビューを適切に活用すれば、row cache lockのホルダーセッション/スタンバイセッションの関係を明確に把握することができます。
row cacheダンプとV$ ROWCACHE_PARENTビューから正確なオブジェクトの情報を確認する方法
上記のダンプファイルから意味のある情報は、以下の通りです。
Shared Sub-Exclusiveモードの意味は、オブジェクト全体には、Sharedモードで、オブジェクトの一部については、Exclusiveモードでロックを獲得することです。Seqneuce.nextval呼び出しによってシーケンスディクショナリ情報が変更されている場合には、シーケンス自体を変更させるのではなく、シーケンスの「次の値」だけを変更させるので、SSXモードでrow cache lockを獲得することになります。
分析事例
Remote Query実行時に発生したRow Cache競合分析
対象DBの8i – >10gの移行作業後監視中latch:row cache objectsイベントの待機が周期的に発生しました。DBをオープンした7月12日12時以降のデータを対象に、Performace AnalyzerのSession List機能を利用してlatch:row cache objectsイベントの発生状況を照会てみます。
SELECT * FROM”DUAL”とSQLを実行するセッションがlatch:row cache objectsイベントを待機しており、SQL文がすべて大文字でテーブル名に””(二重引用符)がされていることを見てリモートで実行されたクエリであることを知ることができます。
latch:row cache objectsイベント発生する状況で、V $ SESSIONビューを照会して、latchのaddressを確認することができます。
EVENT#205番latch:row cache objectsを待機するセッションは同じラッチaddressを持っていることをP1RAWカラムを介して知ることができます。(C0000001B7C03BC8)
latch:row cache objectsイベントを待機と同じ視点にrow cache lockイベントを待機するセッションも確認することができます。
特に、latch:row cache objectsイベントを待機するセッションが実行されたSQLが同一です。
また、row cache lockのrow cache id=16回であることを知ることができます。
row cache lockが発生したセッションのcache idをV$ ROWCACHEビューを介して照会すると、結果は次の通りです。
16番row cacheの使用回数(USAGE)とリクエストすることができ(GETS)は、要求が失敗することができ(GETMISSES)が高くなっています。Row Cacheは、Oracleのdictionary meta情報を提供するため、大気や競合が発生しないことがいいので、dc_histogram_defsディクショナリオブジェクトについての任意の部分で使用されるオブジェクトであることを確認しなければなりません。
オラクルメタリンクを探してみると、Remote Queryを実行するとき、local DBのテーブル、カラムのヒストグラムを参照するためにdc_histogram_defsディクショナリにアクセスするため、この時shared poolの負荷が発生する不具合があります。(Oracleの8バージョンまで存在していました。)
このような状況を考慮して10gにも再発されていないことを、Oracleにお問い合わせすることが望ましいものと考えます。