web-dev-qa-db-ja.com

削除ステートメントのデッドロック

SQL Serverジョブを実行すると、デッドロックが発生します。デッドロックは、単純なDELETEステートメントで発生します。デッドロックを引き起こすためにSELECT/UPDATEクエリを実行する必要があると思いましたか?しかし、それはDELETE/DELETEデッドロックのように見えます...

私が探しているのは、DELETE/DELETEデッドロックが発生する理由です。 (私の知る限りでは)異なるパラメーターを渡すことです。

何か案は?ありがとう。

deadlock-list
2014-05-20 07:30:09.66 spid25s      deadlock victim=process409048
2014-05-20 07:30:09.66 spid25s       process-list
2014-05-20 07:30:09.66 spid25s        process id=process409048 taskpriority=0 logused=0 waitresource=PAGE: 12:1:7127294 waittime=4352 ownerId=629860973 transactionname=DELETE lasttranstarted=2014-05-20T07:30:05.307 XDES=0x397219620 lockMode=U schedulerid=5 kpid=3792 status=suspended spid=150 sbid=0 ecid=3 priority=0 trancount=0 lastbatchstarted=2014-05-20T07:30:05.307 lastbatchcompleted=2014-05-20T07:30:05.307 clientapp=QSQL25 hostname=MORRIS hostpid=1528 isolationlevel=read committed (2) xactid=629860973 currentdb=12 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
2014-05-20 07:30:09.66 spid25s         executionStack
2014-05-20 07:30:09.66 spid25s          frame procname=adhoc line=1 stmtstart=68 sqlhandle=0x020000000b887a18f75d0aa07c25a9b8630fca696aa0e5d2
2014-05-20 07:30:09.66 spid25s     DELETE FROM dbo.UserDetailsData WHERE        (Username = @P1) AND (UserDate = @P2)     
2014-05-20 07:30:09.66 spid25s          frame procname=unknown line=1 sqlhandle=0x000000000000000000000000000000000000000000000000
2014-05-20 07:30:09.66 spid25s     unknown     
2014-05-20 07:30:09.66 spid25s         inputbuf
2014-05-20 07:30:09.66 spid25s        process id=process432e08 taskpriority=0 logused=0 waitresource=PAGE: 12:1:7127916 waittime=2648 ownerId=629859744 transactionname=DELETE lasttranstarted=2014-05-20T07:30:04.833 XDES=0x4c3426b50 lockMode=U schedulerid=6 kpid=5988 status=suspended spid=146 sbid=0 ecid=3 priority=0 trancount=0 lastbatchstarted=2014-05-20T07:30:04.833 lastbatchcompleted=2014-05-20T07:30:04.820 clientapp=QSQL25 hostname=MORRIS hostpid=1528 isolationlevel=read committed (2) xactid=629859744 currentdb=12 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
2014-05-20 07:30:09.66 spid25s         executionStack
2014-05-20 07:30:09.66 spid25s          frame procname=adhoc line=1 stmtstart=68 sqlhandle=0x020000000b887a18f75d0aa07c25a9b8630fca696aa0e5d2
2014-05-20 07:30:09.66 spid25s     DELETE FROM dbo.UserDetailsData WHERE        (Username = @P1) AND (UserDate = @P2)     
2014-05-20 07:30:09.66 spid25s          frame procname=unknown line=1 sqlhandle=0x000000000000000000000000000000000000000000000000
2014-05-20 07:30:09.66 spid25s     unknown     
2014-05-20 07:30:09.66 spid25s         inputbuf
2014-05-20 07:30:09.66 spid25s        process id=process39ea562c8 taskpriority=0 logused=0 waitresource=PAGE: 12:1:7127916 waittime=4352 ownerId=629860973 transactionname=DELETE lasttranstarted=2014-05-20T07:30:05.307 XDES=0x13e0e4b50 lockMode=U schedulerid=2 kpid=7124 status=suspended spid=150 sbid=0 ecid=1 priority=0 trancount=0 lastbatchstarted=2014-05-20T07:30:05.307 lastbatchcompleted=2014-05-20T07:30:05.307 clientapp=QSQL25 hostname=MORRIS hostpid=1528 isolationlevel=read committed (2) xactid=629860973 currentdb=12 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
2014-05-20 07:30:09.66 spid25s         executionStack
2014-05-20 07:30:09.66 spid25s          frame procname=adhoc line=1 stmtstart=68 sqlhandle=0x020000000b887a18f75d0aa07c25a9b8630fca696aa0e5d2
11
K09

私が探しているのは、DELETE/DELETEデッドロックが発生する理由です。

デッドロックは次の理由で発生するようです。

  1. spid 54 ecid 0PAGE: 12:1:5147422の更新(U)ページロックを取得します
  2. spid 166 ecid 3は、同じページの更新(U)ページロックを要求し、ブロックされます
  3. spid 54 ecid 2は、同じページの更新(U)ページロックを要求します...

クエリのためにページがプリフェッチされ、更新ロックはecid 0によって取得されます。それが上記のステップ1です。手順3では、同じ並列クエリ(ecid 2)の子スレッドが同じロックを要求します。通常、これは問題にはなりません。 SQL Serverは、ecid 0ecid 2が同じ親プロセスのスレッドであることを認識しています。残念ながら、ステップ2はこれを妨げ、デッドロックが発生します。

とはいえ、デッドロックが発生する理由理由をあまり気にする必要はありません。重要な問題は、それをどのように回避するかです。答えは、DELETEに効率的なアクセスパスを提供することです。ステートメントは行WHERE Username = @P1 AND UserDate = @P2を見つける必要があるため、これらの列にキー付けされたインデックスが必要です。

そしてもちろん、あなたはそのようなインデックスを持っています。 本当の質問は、フィルターされたインデックスを追加した後に問題が発生し始めた理由です。

その答えは、削除するフィルター処理されたインデックス行を見つける(およびその述語をチェックする)ために追加の列情報が必要であるということです。クエリが narrow/per-row実行プラン を使用する場合、実行エンジンは、ワイド/インデックスごとのプランの場合のように、クラスター化インデックス削除演算子で追加の列をフェッチできません。

あなたはそれについてより多くの詳細と実際の例 このブログ投稿で を見つけることができます。

この場合、列情報は計画の一部であるクラスター化インデックス削除の右側にある必要があるため、並列クラスター化インデックススキャンが使用され、デッドロックの可能性が高い低速のクエリが取得されます。

答えは、次のいずれかを実行することです。

  1. フィルターされたインデックスを削除する
  2. フィルターされたインデックスキー/インクルード/述語列を既存の名前/日付インデックスに追加する
  3. 幅広い更新プランを強制します(サポートされていませんこれを行う方法はありません)
  4. (RCSIではなく)スナップショット分離の下でクエリを実行する

オプション2は私の好みです

オプション4(Jack Douglasに感謝)には、デッドロックを削除するという利点があり、 not not は「更新の競合」を引き起こします。これは、変更の素性を考えると、スナップショット分離を有効にする必要があります。データベースレベルで、分離レベルを明示的に変更し、は根本的な問題を修正しません:それでも無駄な並列テーブルスキャンが行われ、Niceインデックスシークが行われますあなたは本当に欲しい。

14
Paul White 9