web-dev-qa-db-ja.com

SQLサーバーでのDELETEのデッドロックの犠牲者として長時間実行のSELECTクエリが失敗する-なぜ、そしてこれを回避する方法は?

まず、1つのスレッドがテーブルから大量のデータを選択します。

次に、SELECTクエリがまだ完了する前に、別のスレッドがそのテーブルからデータを削除します。

これにより、エラーerrorCode = 1205 sqlState = 40001でSELECTクエリが失敗し、デッドロックが発生したというメッセージが表示されます。

2番目のトランザクションは最初のトランザクションが終了するまで待つ必要があるか、または最初のトランザクションは2番目のトランザクションによって行われた変更なしでデータを返す必要があると考えました。どうすればこれを回避できますか?

トランザクションの順序を変更したり、何らかの方法でそれらを制御したりすることはできません(アプリのユーザーは多く、いつでも好きな順序で好きなことができます)。なぜそれが起こるのですか?

クエリは次のようになります(少し難読化しました)。

SELECT distinct P.pID, (LastNAME+' '+FirstName+' '+SurName) as NAME, 'person' as Type, CA.OrgName, PC.personemail as Email
FROM Persons P
INNER JOIN WORK PW ON (P.mainwork = PW.pwId)
INNER JOIN CONTACT PC ON (PC.pID = P.pID)
LEFT OUTER JOIN ORG CA ON (CA.orgId = PW.orgId)
WHERE (P.Status = ?)

そして

DELETE FROM persons WHERE id = 1234
1
saroff

2番目のトランザクションは最初のトランザクションが終了するまで待たなければならないと思った

基本的に、これは真実ではありません。あなたの(または誰かの)データベースは、一度に1人しか操作できない場合、あまり効率的ではありません。

なぜそれが起こるのですか?

単に:

SELECTクエリは、参照しているすべての行で共有ロックを取得しているため、別のSELECTクエリと競合することはありませんが、DELETEからの排他ロックとは競合します。 SELECTクエリは何も更新しないので、通常はデッドロックの被害者になります。これは ロールバックに最もコストがかかる可能性があります。

あなたが話している場合に特にそれが起こる理由は、それ以上の情報なしには言えません。最後にデッドロック検出へのリンクをいくつか追加しますが、これは質問の主な目的ではないので...

何をしますか?

あなたにとって最善のアプローチが何であるかを知ることは困難です(多くの情報なしでは)。分離レベルを確認する必要がある可能性があります。

READ_COMMITTED_SNAPSHOTを使用することもできますが、これによりさらにオーバーヘッドが発生したり、READ_UNCOMMITEDを使用したり、NOLOCKヒントを使用したりできます。返されたデータは実際には望んでいない可能性があるため、私は通常これらのオプションのファンではありませんが、あなたの場合。それはあなたのシステムとそれの使用に関する多くの異なる変数に依存するので、何が最良であるかを正確に言うのは難しいです。

あなたがその点であなたができる最善のことは分離レベルについて読まれていますが、これらはあなたを始めてより詳細に行くいくつかの同様の投稿/ソースです。

MSDN-selectステートメントはどのようにしてデッドロックの犠牲者として選択されるのですか?SQL Server centralMSDN-分離レベルについて

しかし...

急いで変更を加えて、クエリを完了できるようにしないでください。探索するためのより適切な手段は、クエリ自体です。

SELECTステートメントの実行に時間がかかるのはなぜですか?テーブルから物が頻繁に削除されるのはなぜですか?簡単なクエリチューニングを行うと、すべてがより速く完了し、デッドロックの可能性が減ります。おそらく、データベースサーバーで一般的なパフォーマンスチューニングを行う必要があるかもしれません(これについては、話題から外れているので、ここでは詳しく説明しません)。

クエリが単に「すべてのコストで完了する」クエリではなく、クエリがビジネス目的に適していることを確認する必要があります。データベースは、何よりもまずビジネスツールであり、それを回避する必要があります(ただし、あまり好きではないかもしれません)。

先に進んで分離レベルを変更するか、またはNOLOCKを使用するだけでも、データベースに大きな影響を与える可能性があり、クエリが返す正確な結果が何であるかは、ビジネスに影響を与える可能性があります。

また...

デッドロックの検出を支援するには、この投稿をご覧ください on StackOverflow およびデッドロック情報ツール MSDNサイト を確認してください。トレースフラグを使用して詳細を提供する方法が説明されていますデッドロックに関する情報。

最後に...

SQL Serverのバージョンを投稿に含めた場合、より具体的なアドバイスを提供できます。SELECTクエリの正確な詳細については、非常に時間がかかり、ロックのために開いている原因となる可能性があるものがないか確認してください。 。

6
Ian_H