SELECT は共有ロックのみを取得するため、他の SELECT とデッドロックすることはありません。あなたは、これらの SELECT が「排他的読み取りロックを必要とする」ことを考慮すべきだとおっしゃいましたが、1) のようなものは存在exlusive read lock
せず、2) 読み取りは排他的ロックを取得しないため、これを考慮することはできません。
しかし、単純なステートメントがデッドロックになる可能性があるかどうかという、より一般的な質問を提起します。答えは明確で、はっきりとYESです。ロックは実行時に取得されます。前もって分析され、ソートされてから、ある順序で取得されるわけではありません。ロックはディスク上の実際のデータに依存するため、エンジンが必要なロックを前もって知ることは不可能であり、エンジンがデータをロックするために必要なデータを読み取ることは不可能です。
単純なステートメント (SELECT と UPDATE または SELECT と DELETE) の間のデッドロックは、インデックス アクセス順序の違いによるもので、非常に一般的であり、調査、診断、および修正が非常に簡単です。ただし、読み取りは互いにブロックできないため、常に書き込み操作が含まれることに注意してください。この説明では、UPDLOCK または XLOCK ヒントを SELECT に追加することは、書き込みと見なす必要があります。JOIN も必要ありません。セカンダリ インデックスは、デッドロックにつながるアクセス順序の問題を引き起こす可能性があります。 Read/Write Deadlock を参照してください。
そして最後に、書くことSELECT FROM A JOIN B
も書くことSELECT FROM B JOIN A
もまったく関係ありません。クエリ オプティマイザは、適切と思われるアクセス順序を自由に再配置できます。クエリの実際のテキストによって実行順序が強制されることはありません。
更新しました
では、デッドロックしない READ COMMITTED の「複数エンティティ」データベースに向けた一般的な戦略をどのように構築できるでしょうか?
残念ながら、クッキーカッターのレシピはありません。解決策はケースバイケースです。最終的に、データベース アプリケーションでは、デッドロックは日常茶飯事です。「月に着陸したが、正しいデータベース アプリケーションを作成できない」のように、これがばかげているように聞こえるかもしれませんが、アプリケーションが最終的にデッドロックに遭遇することをほぼ保証する強力な要因が作用しています。幸運なデッドロックは、エラーに対処するのが最も簡単で、単純に状態を再度読み取り、ロジックを適用し、新しい状態を書き直します。そうは言っても、デッドロックの頻度を劇的に減らすことができるいくつかの良い方法があります。
- Writesの一貫したアクセス パターンを持つようにしてください。
Customers
「トランザクションは常に次の順序でテーブルを作成する必要があります: -> OrderHeaders
-> 」などのルールを明確に定義しますOrderLines
。transaction内では順序に従わなければならないことに注意してください。基本的に、スキーマ内のすべてのテーブルをランク付けし、すべての更新がランキング順に発生する必要があることを指定します。これは最終的に、コードを書いている個々の貢献者のコード規律に帰着します。トランザクション内で適切な順序で書き込みが更新されることを保証する必要があるからです。
- 書き込み時間を短縮します。通常の知恵は次のとおりです。トランザクションの開始時にすべての読み取りを行い (既存の状態を読み取ります)、ロジックを処理して新しい値を計算し、トランザクションの最後にすべての更新を書き込みます。'read->write->logic->read->write' のようなパターンは避け、代わりに 'read->read->logic->write->write' を実行します。もちろん、真の職人技は、実際の、実際の、個々のケースに対処する方法にあります。トランザクション中に書き込みを行う必要があります。ここで、特定のタイプのトランザクションについて特に注意する必要があります。キューによって駆動されるトランザクションは、定義上、キューからデキュー (= 書き込み) することによってアクティビティを開始します。これらのアプリケーションは、常に作成が難しく、エラー (特にデッドロック) が発生しやすいことで知られていましたが、幸いなことにそれを行う方法があります。 Using tables as Queues を参照してください。
- 読み取り量を減らします。テーブル スキャンは、デッドロックの最も一般的な原因です。適切なインデックス作成により、デッドロックが解消されるだけでなく、プロセスのパフォーマンスも向上する可能性があります。
- スナップショット分離。これは、デッドロックを回避するという点で、無料のランチに最も近いものです。他の問題 (不適切なインデックス作成など) を修正する代わりに隠す可能性があるため、意図的に最後に配置しました。
LockCustomerByXXX
私が恐れているアプローチでこの問題を解決しようとしてもうまくいきません。悲観的ロックはスケーリングしません。楽観的な同時実行更新は、何らかの適切なパフォーマンスが必要な場合に最適な方法です。