分離およびロックによる並行性制御

TimesTenのトランザクションでは、ANSIシリアライズ可能分離レベルおよびANSIコミット読取り分離レベルがサポートされています。

ANSIシリアライズ可能分離レベルは、最も厳密なトランザクションの分離レベルです。ANSIコミット読取りに設定すると、同時実行性をより高くできます。デフォルトはコミット読取りで、これはほとんどのアプリケーションに適した分離レベルです。

次の項では、トランザクションの分離レベルおよびロック・レベルについて説明します。

トランザクションの分離レベル

トランザクションに独立性があることで、アクティブな各トランザクションは、他のアクティブなトランザクションがシステム内に存在していない場合と同様に動作できます。

分離レベルでは、読取り処理の実行時に行レベル・ロックを設定するかどうかを決定します。表を更新するために文が発行されると、更新トランザクションがコミットまたはロールバックされてそのロックが解放されるまで、他のトランザクションが同じデータを変更しないようにロックが設定されます。

Isolation接続属性では、接続の分離レベルを設定します。分離レベルをトランザクション中に変更することはできません。

TimesTenでは、次の2つのトランザクション分離レベルがサポートされています。

  • ANSIコミット読取り分離: コミット読取り分離レベルは、ほとんどのアプリケーションに適した処理モードで、デフォルト・モードでもあります。これによって、データを読み取っているトランザクションを、同じデータを更新している他のトランザクションと同時に実行できるようになります。TimesTenでは、データ項目の複数のバージョンが作成されるため、シリアライズ可能ではない読取りおよび書込み処理をパラレルで実行できます。

    同じデータの読取りおよび書込みが行われる場合も、読取り処理により書込み処理がブロックされることも、書込み処理により読取り処理がブロックされることもありません。読取り処理では、スキャンされた行にロックを設定しません。書込み処理では、トランザクションがコミットまたはロールバックされるまで、ロックを設定します。読取りユーザーはコミットされたデータのコピーを共有し、書取りユーザーは非コミット・バージョンを保有します。したがって、実行中のトランザクションによって更新処理が行われている項目を別のトランザクションで読み取ると、その項目のコミットされたバージョンが表示されます。処理中のトランザクションの非コミット・バージョンは表示されません。

    コミット読取り分離レベルでは、トランザクション内の非リピータブル・リードまたはファントム行のため分離度が低下するかわりに、同時実行性が向上します。アプリケーションが同じトランザクション内で同じ問合せを何度も実行すると、別のトランザクションからの更新のコミットによって、2番目の読取り処理の結果が別のものになることがあります。トランザクション時に読取りのロックが早く解放されると、ファントム行が同じトランザクション内の2つの異なる読取り処理に(変更された形式で)表示される可能性があります。

    コミット読取り分離レベルを設定するには(このデフォルト設定が変更されている場合)、次のいずれかの処理を行います。

    • Isolation接続属性を1に設定して接続します。この値は、ALTER SESSION SQL文で変更することもできます。

      ALTER SESSION SET ISOLATION_LEVEL=READ COMMITTED;

      Oracle TimesTen In-Memory Databaseリファレンス分離またはOracle TimesTen In-Memory Database SQLリファレンスALTER SESSIONを参照してください。

    • ttIsqlを使用している場合は、isolation 1またはisolation READ_COMMITTEDを実行します。

    • ODBCアプリケーションで、SQL_TXN_ISOLATIONフラグをSQL_TXN_READ_COMMITTEDに設定し、ODBC関数SQLSetConnectOptionを実行できます。『Oracle TimesTen In-Memory Database C開発者ガイド』ODBC 2.5のSQLSetConnectOptionおよびSQLGetConnectOptionのオプションのサポートを参照してください。

    • JDBCアプリケーションで、ConnectionオブジェクトのsetTransactionIsolation JDBCメソッドをTRANSACTION_READ_COMMITTEDに対して実行できます。

  • ANSIシリアライズ可能分離レベル: トランザクション内で読取り処理または書込み処理によって設定されたすべてのロックは、トランザクションがコミットまたはロールバックされるまでそのままになります。読取り処理によって書込み処理がブロックされ、書込み処理によって読取り処理がブロックされます。ただし、読取り処理は他の読取り処理をブロックしません。

    • 最初のトランザクションが行を読み取る場合、2番目のトランザクションもその行を読み取ることができます。

    • 最初のトランザクションによって読み取られた行は、最初のトランザクションがコミットまたはロールバックされるまで、2番目のトランザクションは更新または削除できません。ただし、2番目のトランザクションは、最初のトランザクションによってロックされている範囲外の行を挿入できます。たとえば、最初のトランザクションが行1から行10を読み取っている場合、2番目のトランザクションは行1から行10を更新できません。ただし、2番目のトランザクションは10より後の行に挿入できます。

    • 最初のトランザクションによって挿入、更新または削除された行には、その最初のトランザクションがコミットまたはロールバックされるまで、2番目のトランザクションはどのような方法でもアクセスできません。

    シリアライズ可能分離レベルでは、同時実行性が低下するかわりに、リピータブル・リードが実現し、分離度が向上します。同じ問合せを同じトランザクション内で複数回実行するトランザクションは、毎回同じ結果セットが戻されることが保証されます。他のトランザクションで、戻された行を更新したり、削除したり、問合せ条件を満たす新しい行に対して挿入を実行することもできません。

    分離レベルをシリアライズ可能分離に設定するには、次のいずれかの処理を行います。

    • Isolation接続属性を0に設定して接続します。この値は、ALTER SESSION SQL文で変更することもできます。

      ALTER SESSION SET ISOLATION_LEVEL=SERIALIZABLE ;

      Oracle TimesTen In-Memory Databaseリファレンス分離またはOracle TimesTen In-Memory Database SQLリファレンスALTER SESSIONを参照してください。

    • ttIsqlを使用している場合は、isolation 0またはisolation SERIALIZABLEを実行します。

    • ODBCアプリケーションで、SQL_TXN_ISOLATIONフラグをSQL_TXN_SERIALIZABLEに設定し、ODBC関数SQLSetConnectOptionを実行できます。

    • JDBCアプリケーションで、ConnectionオブジェクトのsetTransactionIsolation JDBCメソッドをTRANSACTION_SERIALIZABLEに対して実行できます。

    マテリアライズド・ビューを常に一貫性がある状態に保つために、すべてのビュー・メンテナンス処理は、トランザクションがコミット読取り分離レベルの場合も、シリアライズ可能分離レベルで実行されます。これは、トランザクションで、ビュー・メンテナンス時に読み取られるすべてのデータ項目に読取りロックを設定することを意味します。ただし、読取りロックは、トランザクションが終了するまで保持されるのではなく、ビュー・メンテナンス処理をトリガーしたINSERTUPDATECREATE VIEW文が終了すると解除されます。

ノート:

ttXactAdminユーティリティで生成されるレポートには、すべての未処理トランザクションに関するロックの保持と待機が表示されます。このレポートは、処理がブロックされたロックの競合問題、またはロック・タイムアウトおよびデッドロックなどのエラーが発生した場合、トラブルシューティングに使用できます。また、特定のトランザクションをロールバックする場合にも使用できます。

ロックの粒度

TimesTenでは、行レベル・ロック、表レベル・ロックおよびデータベース・レベル・ロックがサポートされています。

異なるロック・レベルの異なる接続が同時に存在することは可能ですが、データベース・レベルのロックを使用する接続が1つでもある場合は、同時実行性が低下します。パフォーマンス情報については、「最適なロック方法の選択」を参照してください。

ノート:

同じトランザクション内で複数のロックが取得されている場合、トランザクションが終了すると、ロックは順次解放されます。

  • 行レベル・ロック: 通常、トランザクションはアクセスする各行にロックを設定します。行レベル・ロックは、同時実行性制御の粒度が最も細かくなるため、処理モードとしてお薦めします。同時実行トランザクションで、同じ表の異なる行を更新できます。ただし、行レベル・ロックには、データベースの一時メモリー領域にロック情報を保存するための領域が必要になります。

    行レベル・ロックはデフォルトです。ただし、別のタイプのロックに変更されている場合で、行レベル・ロックを再度有効にする場合は、次のいずれかの処理を行います。

    • LockLevelの接続属性を0に設定します。

    • TimesTen Classicでは、lockLevelパラメータをRowに設定してttLockLevel組込みプロシージャをコールします。このプロシージャは、次のトランザクション、およびこの接続でその後に実行されるすべてのトランザクションの行レベル・ロックとデータベース・レベル・ロックを変更します。

    • ttOptSetFlag組込みプロシージャを実行して、RowLockパラメータを1に設定すると、オプティマイザで行ロックの使用を選択できます。

    ノート:

    『Oracle TimesTen In-Memory Databaseリファレンス』LockLevelttLockLevelおよびttOptSetFlagを参照してください。

  • 表レベル・ロック: 表レベル・ロックは、同時実行トランザクションで他の表にアクセスする場合や、トランザクションで特定の表のほとんどの行にアクセスする場合にお薦めします。表レベル・ロックでは、データベース・レベル・ロックに比べ、同時実行性が高くなります。行レベル・ロックでは、表レベル・ロックに比べ、同時実行性が高くなります。表レベル・ロックでは、一時メモリー領域にわずかな領域があれば、ロック情報を保存できます。

    表レベル・ロックでは、次の場合に最大のパフォーマンスが得られます。

    • 問合せで表の多数の行にアクセスする場合

    • 表にアクセスする同時トランザクションの数が非常に少ない場合

    • 一時領域が不十分で、大量の挿入または削除などの処理で設定する可能性がある行ロックをすべて格納できない場合

    表レベル・ロックを有効にするには、ttOptSetFlagプロシージャを実行して、TblLockパラメータを1に設定すると、オプティマイザで行ロックの使用を選択できます。また、オプティマイザで行レベル・ロックの使用を選択しない場合は、RowLockを0に設定します。

    表レベル・ロックと行レベル・ロックの両方が無効になっている場合、TimesTenではデフォルトで行レベル・ロックが設定されています。表レベル・ロックと行レベル・ロックの両方が有効になっている場合、TimesTenはパフォーマンスが高いと予想されるロック・スキームを選択します。表レベル・ロックはロック処理のオーバーヘッドが少ないため、行レベル・ロックよりも高いパフォーマンスが得られますが、オプティマイザでは多くの場合、同時実行性が高い行レベル・ロックが選択されます。詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』ttOptSetFlagを参照してください。

  • データベース・レベル・ロック: データベース・レベル・ロックは、すべてのトランザクションをシリアライズし、データベースの同時実行性を実質的に禁止します。トランザクションを開始すると、データベースに排他ロックが設定され、データベース内のアクティブなトランザクション数は常に1つになります。トランザクションが完了すると、ロックが解除されます。

    データベース・レベル・ロックは、ロック処理のオーバーヘッドが少ないため、行レベル・ロックより高いパフォーマンスが得られます。また、バルク・ロード処理など、単一のトランザクション・ストリームを実行する場合、行レベル・ロックに比べスループットが高くなります。ただし、このロックは、複数の同時トランザクションを実行することがないアプリケーションにのみ適用されます。データベース・レベル・ロックを設定すると、同時トランザクションが許可されないため、すべてのトランザクションがANSIシリアライズ可能分離レベルで効率的に実行されます。

    データベース・レベル・ロックを有効にするには、次のいずれかの処理を行います。

    • LockLevelの接続属性を1に設定します。

    • TimesTen Classicでは、lockLevelパラメータをDSに設定してttLockLevel組込みプロシージャをコールします。このプロシージャは、次のトランザクション、およびこの接続でその後に実行されるすべてのトランザクションの行レベル・ロックとデータベース・レベル・ロックを変更します。

ロック取得の待機時間の設定

LockWait接続属性を、文がロックの設定を待機する、この時間をすぎるとタイムアウトする最長時間に設定します。デフォルトは10秒です。トランザクション内の文がロックを待機していて、ロック待機時間が過ぎた場合は、エラーが戻されます。エラーを受信した後、アプリケーションは文を再発行できます。

ロック・タイムアウトを検出するためのデータベースの管理サブデーモン・プロセスのスケジュールにより、ロック待機時間は正確ではありません。タイムアウトが0秒に設定されている場合はすぐにレポートされるため、不正確ではありません。ロック待機時間は、ブロッキング・チェックポイントには適用されません。

データベースの管理サブデーモン・プロセスでは、同時実行トランザクションの中にデッドロックがないか、2秒ごとにデータベースをチェックします。デッドロックが発生した場合、デッドロック・サイクルに入ったトランザクションのうちの1つにエラーが戻されます。デッドロックが発生したもう一方のトランザクションが実行できるようになるには、エラーを受け取ったトランザクションをロールバックする必要があります。

ロック競合の可能性が高いワークロードを実行する際には、LockWait接続属性を小さい値に設定してアプリケーションに制御を迅速に戻すか、LockWaitを大きな値に設定してロック付与率を増加する(スループットが減少するリスクがある)ことを検討してください。

『Oracle TimesTen In-Memory Databaseリファレンス』LockWaitを参照してください。