複雑な選択クエリと巨大なテーブルがあります。
私はこのselect
ステートメントを実行していますが、その間にUpdate
ステートメントが到着し、テーブルを更新しようとします。
私見-更新には排他ロックが必要です-したがって、選択コマンドが完了するまで更新ステートメントを待機する必要があります。
私は正しいですか?
select
複合体を実行し、update
コマンドを実行させるために何ができますか(現在、ダーティデータは気にしません)
複雑な選択クエリと巨大なテーブルがあります。
私はこのselect
ステートメントを実行していますが、その間にUpdate
ステートメントが到着し、テーブルを更新しようとします。
私見-更新には排他ロックが必要です-したがって、選択コマンドが完了するまで更新ステートメントを待機する必要があります。
私は正しいですか?
select
複合体を実行し、update
コマンドを実行させるために何ができますか(現在、ダーティデータは気にしません)
はい-ある程度。
SELECT
共有ロックを保持する期間は、トランザクションの分離レベルによって異なります。
READ UNCOMMITTED
-共有ロックはまったく取得されUPDATE
ません-ブロックされませんREAD COMMITTED
-共有ロックはデータの読み取り中にのみ取得されます-UPDATE
非常に短時間ブロックされる可能性がありますREPEATABLE READ
およびSERIALIZABLE
-共有ロックが取得され、トランザクションが終了するまで保持されます-トランザクションが終了するUPDATE
までブロックされますSELECT
技術的には、UPDATE
ステートメントは最初に、更新される行の現在の値を読み取っている間、UPDATE
(で使用される)共有ロックと互換性のあるロックを取得します。SELECT
それが完了すると、Update
ロックはテーブルに書き込まれる新しいデータの排他的ロックにエスカレートされます。
2 つのステートメント (SELECT と UPDATE) を同時に実行すると、実際の動作は基本的にランダムになります。これは、どちらの操作も瞬時ではないためです。簡単にするために、テーブルをリストと考えてください。SELECT はこのリストを走査し、一度に 1 行ずつ調べます。UPDATE も 1 つ以上の行を更新しようとしています。UPDATE が SELECT の背後で行を更新しようとしている場合、SELECT はすでに UPDATE ポイントを通過しているため、何も起こりません (ブロッキングは発生しません)。UPDATE が SELECT が現在探している行を更新しようとしている場合、UPDATE はSELECT が先に進むのを待たなければなりません。これは非常に高速に行われ、UPDATE はブロックを解除して成功します。SELECT は前進しています。しかし、UPDATE がSELECTよりも先に行を更新している場合、更新は成功し、その後、SELECT は最終的に正確にこの行に到達し、停止してブロックされます。SELECT は、UPDATE を実行したトランザクションがコミットされるまで待機する必要があります。
これは単純化した話です。実際の生活はもっと複雑です。SELECT は複数の読み取りポイントを持つことができます (並列プラン)。SELECT と UPDATE はどちらもアクセス パスの選択に左右されます。つまり、1 つ以上のセカンダリ インデックスを使用して行を検索します。複雑なクエリには、テーブルへの複数のルックアップを引き起こす演算子が含まれている場合があります (結合など)。SELECT と UPDATE の両方で、ブックマーク ルックアップを実行して BLOB データを取得できます。これにより、ロック動作が大幅に変更されます。カーディナリティの推定により、SELECT が高粒度のロック モード (テーブル レベルの共有ロックなど) で実行される場合があります。UPDATE はロックのエスカレーションをトリガーすることができ、エスカレーションは失敗または成功する可能性があります。異なるアクセス パスを選択すると、デッドロックが発生する可能性があります。ハッシュの衝突により、誤ったロック競合が発生する可能性があります. これには、無数の変数があります。また、より高い分離レベル (反復可能読み取り、シリアライズ可能) についても言及しませんでした。
おそらく、SNAPSHOT分離を使用して、この問題について心配する必要はありませんか?