Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (日本語) » SQL Anywhere サーバ - SQL の使用法 » データベースの作成 » トランザクションと独立性レベルの使用 » ロックの仕組み

 

クエリ時のロック

ユーザが SELECT 文を入力したときに SQL Anywhere が使用するロックは、トランザクションの独立性レベルによって異なります。すべての SELECT 文は、独立性レベルに関係なく、参照先テーブルでスキーマ・ロックを取得します。

独立性レベル 0 の SELECT 文

独立性レベル 0 で SELECT 文を実行するときは、ロック・オペレーションは必要ありません。各トランザクションは他のトランザクションによる変更から保護されません。プログラマまたはデータベース・ユーザは、この制限を念頭においてこのようなクエリの結果を解釈する責任があります。

独立性レベル 1 の SELECT 文

独立性レベル 1 でトランザクションを実行する場合、SQL Anywhere は独立性レベル 0 で実行するときほど多くのロックを使用しません。それぞれのレベルでデータベース・サーバのオペレーションが異なる点は、2 つしかありません。

オペレーションの最初の違いはロックの設定とは無関係で、むしろロックへの配慮に関するものです。独立性レベル 0 では、別のトランザクションが書き込みロックを取得しても、トランザクションはすべてのローを読み込むことができます。一方独立性レベル 1 のトランザクションは、各ローを読み込む前に書き込みロックがかかっているかをチェックします。書き込みロックがかかっているローは読み込むことができません。この場合、ダーティ・データを読み込むことになるからです。READPAST ヒントを使用すると、サーバは書き込みロックがかかっているローを無視できます。ただし、トランザクションのブロックがなくなると、READPAST ヒントのセマンティックは独立性レベル 1 のセマンティックと一致しなくなります。FROM 句にある READPAST ヒントに関する説明を参照してください。

オペレーションの 2 番目の違いは、カーソル安定性に影響します。カーソル安定性は、カーソルの現在のローに短期間の読み込みロックを設定して達成されます。この読み込みロックはカーソルを移動すると解放されます。カーソルの内容がジョインの結果を示している場合は、複数のローが影響を受けます。この場合、データベース・サーバはカーソルの現在のローに情報を提供したすべてのローに短期間の読み込みロックをかけ、カーソルの別のローが現在のローになるとこれらのロックを解放します。

独立性レベル 2 の SELECT 文

独立性レベル 2 では、データベース・サーバはそのオペレーションを修正し、繰り返し可能読み出しのセマンティックを保証します。SELECT 文がテーブルのすべてのローから値を返す場合、データベース・サーバはローを読み込むときに各ローに読み込みロックをかけます。SELECT に WHERE 句や結果におけるローを制限する他の条件が含まれている場合は、データベース・サーバは各ローを読み込み、ローの値が条件を満たしているかをテストし、条件を満たすローに読み込みロックをかけます。取得された読み込みロックは、長期間の読み込みロックであり、暗黙的または明示的な COMMIT 文または ROLLBACK 文によってトランザクションが完了するまで保持されます。独立性レベル 1 と同じように、独立性レベル 2 ではカーソル安定性が保証され、ダーティ・リードは許可されません。

独立性レベル 3 の SELECT 文

独立性レベル 3 では、データベース・サーバはすべてのトランザクションが直列化可能であることを確認する必要があります。特に、独立性レベル 2 での要件に加えて、同じ文を再実行するとすべての環境で同じ結果を返すことが保証されるように、幻ローを防ぐ必要があります。

この要件を満たすために、データベース・サーバは読み込みロックと幻ロックを使用します。独立性レベル 3 でSELECT 文を実行すると、データベース・サーバは結果セットの計算で処理される各ローで読み込みロックを取得します。こうすることで、そのトランザクションが完了するまで他のトランザクションがそれらのローを修正できないようにします。

この要件は、データベース・サーバが独立性レベル 2 で実行するオペレーションと似ていますが、これらのローが SELECT 文の WHERE 句、ON 句、または HAVING 句の述部を満たすかどうかに関係なく、読み込まれた各ローにロックをかけなければならない点が異なります。たとえば、販売部のすべての従業員名を選択する場合、サーバはトランザクションが独立性レベル 2 または 3 のどちらで実行されているかに関係なく、販売部の従業員に関する情報が含まれているすべてのローにロックをかける必要があります。ただし、独立性レベル 3 では、販売部に所属しない従業員のローにも読み込みロックをかける必要があります。そうでない場合、最初のトランザクションが実行されている間に、別のトランザクションが別の従業員を販売部に移動する可能性があります。

読み込まれた各ローに読み込みロックをかける必要がある場合、次の 2 つの影響があります。

  • データベース・サーバは、独立性レベル 2 で必要とされるロックよりも多くのロックをかけなければならない場合がある。取得される幻ロックの数は、スキャンのために取得される読み込みロックの数よりも 1 つ多くなります。倍増したロックのオーバーヘッドは、要求の実行時間に追加されます。

  • 各ローの読み込みで読み込みロックを取得すると、同じテーブルに対するデータベース更新オペレーションの同時実行性に悪影響がある。

データベース・サーバが取得する幻ロックの数には大きな幅があり、クエリ・オプティマイザによって選択された実行方式によって異なります。SQL Anywhere クエリ・オプティマイザは、システム全体の同時実行性に悪影響を与える可能性があるため、独立性レベル 3 での逐次スキャンを回避しようとします。しかし、このようなオプティマイザの機能は、文の述部と、参照先テーブルで利用できる適切なインデックスに依存します。

たとえば、Employee ID 123 の従業員に関する情報を選択したいとします。Employee ID は従業員テーブルのプライマリ・キーであるため、ローを効率的に検索するために、クエリ・オプティマイザがプライマリ・キー・インデックスを使用するインデックス方式を選択しようとするのはほぼ確実です。さらに、プライマリ・キーの値はユニークであるため、別のトランザクションが他の EmployeeID を 123 に変更する危険性もありません。サーバは、従業員 123 に関する情報を含むローに読み込みロックをかけるだけで、別の従業員にその ID 番号が割り当てられることを防止できます。

一方、販売部の全従業員を選択する場合は、読み込みロック以外のロックもかける必要があります。適切なインデックスがないため、データベース・サーバは従業員テーブルの各ローを読み込み、各従業員が販売部に所属するかどうかをテストする必要があります。この場合は、テーブルの各ローに読み込みロックと幻ロックの両方を設定する必要があります。

SELECT 文とスナップショット・アイソレーション

snapshot、statement-snapshot、または readonly-statement-snapshot で実行される SELECT 文では、読み込みロックを取得しません。これは、各スナップショット・トランザクション (または文) は、以前のある時点における、コミットされた状態のデータベースのスナップショットを認識するためです。この特定の時点は、3 種類あるスナップショット・アイソレーションのレベルのうちどれが文で使用されるかによって決まります。つまり、読み込みトランザクションが更新トランザクションをブロックしたり、更新トランザクションが読み込みトランザクションをブロックしたりすることはありません。そのため、スナップショット・アイソレーションを使用すると、一貫性という明白な長所だけでなく、同時実行性という重要な長所を得ることができます。ただし、トレードオフとして、スナップショット・アイソレーションは非常にコストがかかることがあります。これは、スナップショット・アイソレーションの一貫性保証では、同時に実行される他のトランザクションのために、変更されたローのコピーを保存、追跡、(最終的に) 削除する必要があるためです。