Enq: TM – contention
目次[非表示]
- 1.基本情報
- 2.待機パラメータと待機時間
- 3.チェックポイントと解決策
基本情報
DMLが実行される間、DMLに関連するオブジェクトへの変更を防止するためにDMLを実行するプロセスは、必ず、そのテーブルに対してTMロックを獲得しなければなりません。TMロックを獲得する過程で競合が発生した場合enq:TM – contentionイベントを待機することになります。
オラクルのConceptマニュアルとReferenceマニュアルでは、ロックの分類を次のように説明している。
上記の説明は、DMLロックとDDLロックという別個のロックが存在するかのように混乱を与える恐れがあります。実際にDMLロックとDDLロックはロックを適切に分類するために付けた名前のことですので、この点に留意してください。
DMLロックは、実際にはTMロックと一致します。 DMLロックはDBA_DML_LOCKSビューで観察可能ですが、このビューは、V$LOCKビューでロックタイプがTMであることだけを抽出して示す役割をします。データベースで許容TMロックの数はDML_LOCKSパラメータで指定することができます。もしDML_LOCKSパラメータの値を0した場合テーブルに対してTMロック獲得されません。この場合、Oracleは、テーブル定義が保護されることを保証するために、すでに存在しているテーブルのDDLを基本的に許可していません。したがってTMロックを獲得していなくても、何の心配もなく、テーブルの特定の行を変更することが可能になります。OPSのような環境でTMロックをグローバルに獲得するために発生するオーバーヘッドを減らすためにDML_LOCKSの値を0に変更したりします。
DDLロックは、実際にはlibrary cache lockと一致します。DDLロックはDBA_DDL_LOCKSビューで観察可能ですが、このビューは、実際には、X$KGLLKビューを適切に処理して表示役割をします。 DDLロックはDBA_DDL_LOCKSビューのほか、X$KGLLK、DBA_KGLLOCKのようなビューを介して観察可能です。
一般的なDMLステートメントは、テーブルに対してTMロックをSub-Exclusive(SX)モードで獲得します。Sub-Exclusiveモード間の相互互換性があるため、複数のセッションが同一のテーブルに対して同時にDMLを実行することが可能です。DMLを実行したセッションは、テーブルの上には、TMロックをSub-Exclusiveモードで獲得し、変更されたデータには、TXロックをExclusiveモードで獲得します。
以下のようにV$LOCKビューでDMLを実行したセッションがどのようなロックをどのモードで獲得しているかを観察することができます。
オブジェクト名54679(ID1)に対応するオブジェクトに対してTMロックをSub-Exclusive(3)モードで獲得していることを確認することができます。TMロックのID1は、テーブルのオブジェクトID(Object ID)に該当します。したがってDBA_OBJECTSビューと結合する任意のテーブルのTMロックかどうかを判断することができます。Sub-Exclusiveモード間での互換性があるため、DMLの間TMロックをめぐる競合が発生しません。したがってenq:TM – contention待機も発生しないのです。TM Lock競合が発生する場合は、通常、次のとおりです。
待機パラメータと待機時間
待機パラメータ
Enq: TM – contention 待機イベントの待機パラメータは以下の通りです。
- P1:Enqueue情報
- P2:Object#
- P3:Table/ Partition情報
待機時間
enqueue待機イベントと同一です。最大3秒まで待ちます。もしTMロックを獲得する場合は獲得するまで待機します。
チェックポイントと解決策
インデックスがない外部キー
Oracle 9iの前には、インデックスがない外部キーカラムがTMロック競合の主な原因でした。Oracle 9iの以前のバージョンには、子テーブルの外部キーカラムにインデックスがない状態で、親テーブルのKeyが変更されると、子テーブルに対してSharedモードやShared-Sub-ExclusiveモードでTMロックを獲得しなければなりませんでした。獲得されたTMロックは、親Keyを変更したトランザクションが終了(commitまたはrollback)されるまで維持されるため、これによる競合が深刻なパフォーマンスの低下現象を起こしたりしていました。しかし、幸いなことに、Oracle9iからのアルゴリズムが改善され、このような競合は発生しません。Oracle 9iの以前のバージョンを使用している場合は、foreign keyカラムに必ずインデックスを作成する習慣を持つ必要があります。
不適切なDDLによるTMロック競合
トランザクションが進行中のテーブルには、基本的にDDLが不可能です。したがって、この場合には、競合によるパフォーマンスの問題は発生しません。次の例を見てみて見ましょう。
Updateが行われて、まだコミットされていないテーブルには、DDLを実行することは不可能です。一方、DDLが実行されているテーブルに対してDMLを実行する場合には、TMロック競合が発生することが可能となります。特定のプロセスがテーブルに対してインデックスを作成する場合は、インデックスが作成されている間、テーブルに対してTMロックをSharedモードで獲得することになります。
TMロックのID1を利用すれば、BIG_OBJECTSというテーブル名を得ることができます。LMODEの値は4であり、Sharedモードを意味します。つまり、create index文はbig_objectsテーブルに対してSharedモードでTMロックを獲得することになります。問題は、このテーブルに対してDMLを実行するセッションはSub-ExclusiveモードでTMロックを獲得しなければならないというものです。 SharedモードとSub-Exclusiveモードでは、互換性がないため、DMLを実行するセッションはDDL実行が完了するまで待機することになり、この時enq:TM – contention待機イベントが発生するようになります。DDLによるTMロック競合を減らすことができる方法としては、次のようなものがあります。
次の例を見てみましょう。
Lock table..を利用して意図的にTMロックを獲得した場合
Lock table …を利用して意図的にTMロックを獲得する場合にはTMロック競合が発生することがあります。
上記のように、セッションAからupdateによってTMロックがSub-Exclusiveモードで獲得された状態では、セッションBがlock tableコマンドを利用してTMロックをExclusiveに獲得しようとした場合、競合が発生することになりenq:TM – contentionイベントを待機することになります。
TMロックによる競合が発生する場合には、ロックホルダー(Lock Holder)セッションで実行されたSQL文を収集することが非常に重要です。TMロックの場合に発生することがある場合が非常に多様であるため、SQLステートメントがなければ、正確な判断が難しい場合が多く存在します。問題が誘発されたSQL文がLock table…構文であり、これにより、TMロック競合が広く行われる場合、アプリケーションの適切な修正で解決することができます。同期のためにテーブル全体にロックをかけることなく、DMBS_LOCKパッケージを使用するか、select…for updateなどを使用してロックの範囲を減らす方法を検討します。
Direct/Parallel Load処理を実行した場合
INSERT / * + APPEND * / INTO …またはSQL * Loaderのdirect path loadなどの一部の機能は、そのテーブルに対してTMロックをExclusiveに獲得します。Direct loadタスクは、SGAを経由せずにデータファイルに直接書き込みを行うので、処理が実行されている間、テーブルにどのような変化も許容してはいけません。したがってTMロックをExclusiveに獲得することにより、テーブルのどのような変更も許可されないことを保証受けなければ作業が可能です。 Direct load処理が実行されている間は、テーブルの任意のDDLやDMLも許されません。したがって、トランザクションが多い時点でDirect loadタスクを実行するときは、TMロック競合による問題が発生する恐れがあることを確認しなければなりません。 SQL*Loaderをparallelモードで実行する場合には、テーブルのTMロックをSharedモードで獲得します。したがって、この場合にも、他のセッションでのDDLやDMLは許されません。