web-dev-qa-db-ja.com

SQL Serverは、選択/更新または複数選択の間でデッドロックします

SQL Serverのデッドロックに関するすべてのドキュメントでは、操作1がリソースAをロックし、次に操作2がリソースBをロックし、操作2がリソースBをロックし、リソースAにアクセスしようとするシナリオについて説明しています。

ただし、ビジーなアプリケーションの一部では、選択と更新の間、または複数の選択の間でデッドロックが発生することがよくあります。デッドロックトレース出力のより細かい点のいくつかは非常にわかりにくいと思いますが、2つの単一の操作の間にデッドロックを引き起こす可能性があるものを本当に理解したいと思います。確かに選択に読み取りロックがある場合、更新は排他ロックを取得する前に待機するだけですか?

これはSQL Server 2005で発生していますが、これが違いを生むとは思いません。

37
Rob West

SQL-Server-Performance.comで Advanced SQL Server locking に関する良い記事をブックマークしました。その記事は、あなたが言及した古典的なデッドロックの状況を超えており、あなたの問題に対する洞察を与えるかもしれません。

13
MicSim

これは、選択が2つの異なるインデックスでロックアウトするのに対し、更新が同じインデックスで逆の順序でロックアウトするために発生する可能性があります。最初のインデックスはアクセスする必要があるすべての列をカバーしていないため、選択には2つのインデックスが必要です。インデックスのキー列を更新する場合は、ロックを取得する必要があるため、更新には2つのインデックスが必要です。

http://blogs.msdn.com/bartd/archive/2006/09/25/770928.aspx には素晴らしい説明があります。推奨される修正には、選択が必要とするすべての列をカバーするインデックスの追加、スナップショット分離への切り替え、または通常は必要ない更新ロックの選択を明示的に強制することが含まれます。

20
David Eison

WITH (UPDLOCK)ロックのヒントについて誰も言及していないことに驚いています。たとえば、デッドロックが発生している場合に非常に便利です。 2つのselect-insertペアが並行して実行されています。

SQL Serverでは、WITH (UPDLOCK)を使用してselectを発行すると、2番目のselectは最初のselectが完了するまで待機します。そうでなければ、共有ロックを取得し、同時に排他ロックにアップグレードしようとすると、デッドロックします。

13
Ben Challenor

テーブル全体ではなく、単一の行をロックするため、単一のクエリ間のロックが発生する可能性があります。

更新クエリはテーブル内のいくつかの行で更新ロックを取得し、選択クエリはテーブル内の他の行で読み取りロックを取得します。次に、更新クエリは、読み取りがロックされている行で更新ロックを取得しようとし、選択クエリは、更新がロックされている行で読み取りロックを取得しようとします。

ロックをエスカレートするとさらに複雑になる可能性があります。つまり、データベースは、トランザクションによってロックされた単一行が多すぎると判断し、テーブルのセクションまたはテーブル全体をロックするようにエスカレートする必要があると判断します。これは、ロックがクエリに直接関係しない行に影響する可能性があることを意味します。

5
Guffa

私の推測では、select-statementがread-lockを取得するのは、update-statementを入手したときに、write-lockにアップグレードする必要があるということです。

書き込みロックにアップグレードするには、他のすべての読み取りロックを削除する必要があります(選択トランザクションが完了します)。ただし、別のプロセスが既に書き込みロックにアップグレードするという素晴らしいアイデアを持っている場合、突然2つのプロセスが読み取りロックを解放するのを待っているので、書き込みロックを取得できます。

更新の選択(UPDLOCK)を使用している場合、書き込みロックを最初から取得するため、デッドロックの問題は発生しません。

5
Rolf Kristensen

トランザクションおよび分離レベルについて適切に読んでください。ある程度密ですが、かなり徹底的で技術的に中立な作業については、 Principles of Transaction Processing を参照してください。それは私の世界を揺るがしました(そして、私にかなりの頭痛を与えました!)。

何に問題があるのか​​、どの分離レベルを使用しているのかわかりません。しかし、これを考慮してください。データベースエンジンが知っているすべての場合、1つのトランザクションで読み取りを行う場合、後で書き込みを行うかどうかをどのように判断できますか?高い分離レベルでは、データが後で書き込みに影響を与える可能性があるため、ファントム読み取りから保護するために、おそらくテーブル全体で読み取りが行われるたびにロックする必要があります。

データの排他的ロックをデータベースが任意の時間待機するようにしますか?全体の分離レベル、および分離トランザクションとして一連の読み取りを不必要に実行しているかどうかを確認してください。ただし、どの程度不潔な読み取りを許容できるかを判断するのは必ずしも容易ではありません...

1
Pontus Gagge

トランザクション分離について読む必要があります: http://msdn.Microsoft.com/en-us/library/ms173763.aspx

0
James L