次のデッドロックxmlがあります
<deadlock>
<victim-list>
<victimProcess id="process3340d548c8" />
</victim-list>
<process-list>
<process id="process3340d548c8" taskpriority="0" logused="1676" waitresource="KEY: 5:72057594083016704 (80e6876e1037)" waittime="4843" ownerId="6974726" transactionname="user_transaction" lasttranstarted="2018-05-25T13:52:16.627" XDES="0x330b1b4458" lockMode="U" schedulerid="1" kpid="34260" status="suspended" spid="201" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-25T13:52:16.657" lastbatchcompleted="2018-05-25T13:52:16.657" lastattention="1900-01-01T00:00:00.657" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="6974726" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink_DeleteByAttributeValueIds" queryhash="0xdc817ac17586cee6" queryplanhash="0x8759f1b16359d45e" line="7" stmtstart="340" stmtend="644" sqlhandle="0x03000500f793ca333699da00eba8000001000000000000000000000000000000000000000000000000000000">
DELETE
AVH
FROM
[model].[AttributeValueHyperlink] AVH
INNER JOIN
@AttributeValueIdsTable AVT
ON
[AVT].EntityId = [AVH].AttributeValueI </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByAttributeValueIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="10" stmtstart="490" stmtend="660" sqlhandle="0x030005006cae724fc899da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValueHyperlink_DeleteByAttributeValueIds]
@AttributeValueId </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByModelItemIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="13" stmtstart="732" stmtend="918" sqlhandle="0x03000500def65a51d299da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC model.AttributeValue_DeleteByAttributeValueIds
@AttributeValueIds = @AttributeValueId </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Generic_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="41" stmtstart="2062" stmtend="2208" sqlhandle="0x0300050096f1cb432e9cda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValue_DeleteByModelItemIds]
@ModelItemIdTabl </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Object_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="25" stmtstart="1088" stmtend="1302" sqlhandle="0x0300050061e52c65069dda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[ModelItem_Generic_Delete]
@ObjectIdTable,
@MarkAsDeleted,
@DeletedBy,
@DeletedO </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 5 Object Id = 1697441121] </inputbuf>
</process>
<process id="process3330f29088" taskpriority="0" logused="1744" waitresource="KEY: 5:72057594083016704 (5b32eda0fe69)" waittime="4575" ownerId="6948390" transactionname="user_transaction" lasttranstarted="2018-05-25T13:52:14.370" XDES="0x331cb2c458" lockMode="U" schedulerid="2" kpid="29596" status="suspended" spid="181" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-25T13:52:14.403" lastbatchcompleted="2018-05-25T13:52:14.390" lastattention="1900-01-01T00:00:00.390" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="6948390" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink_DeleteByAttributeValueIds" queryhash="0xdc817ac17586cee6" queryplanhash="0x8759f1b16359d45e" line="7" stmtstart="340" stmtend="644" sqlhandle="0x03000500f793ca333699da00eba8000001000000000000000000000000000000000000000000000000000000">
DELETE
AVH
FROM
[model].[AttributeValueHyperlink] AVH
INNER JOIN
@AttributeValueIdsTable AVT
ON
[AVT].EntityId = [AVH].AttributeValueI </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByAttributeValueIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="10" stmtstart="490" stmtend="660" sqlhandle="0x030005006cae724fc899da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValueHyperlink_DeleteByAttributeValueIds]
@AttributeValueId </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByModelItemIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="13" stmtstart="732" stmtend="918" sqlhandle="0x03000500def65a51d299da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC model.AttributeValue_DeleteByAttributeValueIds
@AttributeValueIds = @AttributeValueId </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Generic_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="41" stmtstart="2062" stmtend="2208" sqlhandle="0x0300050096f1cb432e9cda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValue_DeleteByModelItemIds]
@ModelItemIdTabl </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Relationship_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="23" stmtstart="1078" stmtend="1302" sqlhandle="0x030005000d989e704f9dda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[ModelItem_Generic_Delete]
@RelationshipIdTable,
@MarkAsDeleted,
@DeletedBy,
@DeletedO </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 5 Object Id = 1889441805] </inputbuf>
</process>
<process id="process330f11fc28" taskpriority="0" logused="32948" waitresource="KEY: 5:72057594083016704 (80e6876e1037)" waittime="2558" ownerId="6941127" transactionname="user_transaction" lasttranstarted="2018-05-25T13:52:13.970" XDES="0x33199a4458" lockMode="U" schedulerid="2" kpid="91236" status="suspended" spid="193" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-25T13:52:21.987" lastbatchcompleted="2018-05-25T13:52:21.983" lastattention="1900-01-01T00:00:00.983" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="6941127" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink_DeleteByAttributeValueIds" queryhash="0xdc817ac17586cee6" queryplanhash="0x8759f1b16359d45e" line="7" stmtstart="340" stmtend="644" sqlhandle="0x03000500f793ca333699da00eba8000001000000000000000000000000000000000000000000000000000000">
DELETE
AVH
FROM
[model].[AttributeValueHyperlink] AVH
INNER JOIN
@AttributeValueIdsTable AVT
ON
[AVT].EntityId = [AVH].AttributeValueI </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByAttributeValueIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="10" stmtstart="490" stmtend="660" sqlhandle="0x030005006cae724fc899da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValueHyperlink_DeleteByAttributeValueIds]
@AttributeValueId </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValue_DeleteByModelItemIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="13" stmtstart="732" stmtend="918" sqlhandle="0x03000500def65a51d299da00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC model.AttributeValue_DeleteByAttributeValueIds
@AttributeValueIds = @AttributeValueId </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Generic_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="41" stmtstart="2062" stmtend="2208" sqlhandle="0x0300050096f1cb432e9cda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[AttributeValue_DeleteByModelItemIds]
@ModelItemIdTabl </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Relationship_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="23" stmtstart="1078" stmtend="1302" sqlhandle="0x030005000d989e704f9dda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[ModelItem_Generic_Delete]
@RelationshipIdTable,
@MarkAsDeleted,
@DeletedBy,
@DeletedO </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.RelationshipPair_DeleteByModelItemIds" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="21" stmtstart="1252" stmtend="1462" sqlhandle="0x03000500bc1cd015159eda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[ModelItem_Relationship_Delete]
@RelationshipIds,
0,
@DeletedBy,
@DeletedOn, </frame>
<frame procname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.ModelItem_Object_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="20" stmtstart="878" stmtend="1076" sqlhandle="0x0300050061e52c65069dda00eba8000001000000000000000000000000000000000000000000000000000000">
EXEC [model].[RelationshipPair_DeleteByModelItemIds]
@ObjectIdTable,
@DeletedBy,
@DeletedO </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 5 Object Id = 1697441121] </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594083016704" dbid="5" objectname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink" indexname="IX_AttributeValueHyperlink_AttributeValueId" id="lock3320f42880" mode="U" associatedObjectId="72057594083016704">
<owner-list>
<owner id="process3330f29088" mode="U" />
</owner-list>
<waiter-list>
<waiter id="process3340d548c8" mode="U" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594083016704" dbid="5" objectname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink" indexname="IX_AttributeValueHyperlink_AttributeValueId" id="lock3320f4fb00" mode="X" associatedObjectId="72057594083016704">
<owner-list>
<owner id="process330f11fc28" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process3330f29088" mode="U" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594083016704" dbid="5" objectname="7b7e4b64-e8dd-4a72-8f98-447678798791.model.AttributeValueHyperlink" indexname="IX_AttributeValueHyperlink_AttributeValueId" id="lock3320f42880" mode="U" associatedObjectId="72057594083016704">
<owner-list>
<owner id="process3340d548c8" mode="U" requestType="wait" />
</owner-list>
<waiter-list>
<waiter id="process330f11fc28" mode="U" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
私が理解できる限り、IX_AttributeValueHyperlink_AttributeValueId
インデックスには3つの行レベルのロックがあります。それらのいくつか(process330f11fc28
)がこのインデックスにXロックを持っている理由はわかりませんが、他のロックにはありません。
また、この削除の実行プランは次のようになります
なぜデッドロックが起こっているのか分かりません。すべて問題ないようです。
ちなみにこれはsql Azureデータベース上にあるため、RCSI分離レベルを使用していますが、トランザクションは(C#
レイヤーで)コミットされた読み取りを使用するように設定されています。
なぜデッドロックが起こっているのか分かりません。
この実行プランの場合、 each row の削除に関連するロック操作のシーケンスは次のとおりです。
U
ロック非クラスター化インデックス(インデックスシークで取得)U
ロッククラスタ化インデックス(削除演算子で取得)X
ロッククラスタ化インデックス(削除演算子で)X
非クラスター化インデックスをロック(削除演算子で)理由はわかりません... process330f11fc28にはこのインデックスにXロックがありますが、他にはありません。
プランにはブロッキング演算子がないため、単純なパイプラインです(大まかに言って、各行は次の行が処理される前にパイプラインの最後に到達します)。
デッドロックが発生すると、1つのプロセス(セッション193)で非クラスター化インデックス行にX
ロックが設定されました(上記の最後のステップ)。セッション181および201は最初のステップでブロックされ、セッション193が排他的にロックした同じ非クラスター化インデックス行セッションで互換性のないU
ロックを取得しようとしました。
細かい説明が多少入りますので、予めご了承ください。
非クラスター化インデックスの更新ロックは、一般的なタイプの変換デッドロックを回避するために、エンジンによって自動的に取得されます。 2つのプロセスが同じリソースでS
ロックを取得し、両方がX
への変換を試みます。お互いがS
をX
に変換するのを防ぐため、デッドロックが発生します。
U
はU
と互換性がありますが、別のS
と互換性がないため、U
ロックを取得すると、これが防止されます。当然、S
ロックは通常RCSIの下では取得されませんが、これらのU
ロックは取得されます。これにより、古いバージョンの行を更新しようとすることが回避されます。
自動U
ロックは、更新操作に行ロケータを提供するテーブルのインスタンスに対してのみ、RCSIの下で行われます。クエリ内の他のテーブル(更新ターゲットへの追加の参照を含む)は、引き続き行のバージョン管理を使用します。
これらの自動U
ロックは、通常の更新ロック(UPDLOCK
ヒントで取得される場合がある)とは異なる有効期間を持っています。通常のU
ロックは、transactionの最後まで保持されます。内部U
ロックはstatementの最後まで保持されますが、例外としてsame plan operator /ロックを取得したは、行が更新に適格でないと推定できます。ロックは即時に解放されますです。
私の記事 Read Committed Snapshot Isolationの下のデータ変更 を参照してください。
この自動U
ロックは、サイクリックデッドロックからの保護を提供しません。トランザクション内でリソースAとリソースBを変更する2つのトランザクションは、逆の順序でデッドロックすることが保証されています。
上記の「変更」には、挿入、更新、削除などが含まれます。
質問の例は、このテーマのバリエーションです。ここで、
X
を保持していますU
の取得を待機していますU
ロックを所有していますU
を取得するために待機しています(セッション201も行R2でU
を取得するために待機していますが、無害な傍観者です。)
明確にするために:上記の正確なデッドロックシーケンスは、質問に示されている正確な実行プランでは発生しません。セッション181は、R2でU
を保持できず、R1でU
を要求できなくなりました。これは、ブロッキングオペレーターがないため、および/または非クラスター化U
ロック。インデックスシークによって検出されたU
ロックされた行は、次のシーク行が処理される前にX
に変換されることが保証されています。
それでも、それが今の声明の計画であるという理由だけで、それがデッドロックが発生したときの計画であったことを意味するものではありません。たとえば、ステートメントレベルの再コンパイルが発生すると、SQL Serverはテーブル変数のカーディナリティを確認できます。これは、代わりにハッシュ結合計画につながる可能性があります。
ハッシュ結合プランでは、テーブル変数の行を使用してハッシュテーブルを作成します。これが完了すると、SQL ServerはAttributeValueHyperlink
から行の読み取りを開始し、インデックススキャンによって発行された各行に対してU
ロックを取得できます(現在、検索するものはありません)。
ハッシュ結合では、各プローブ側の行が結合述語に対して評価されます。一致が見つかった場合、行はクラスター化インデックス削除演算子に進み、クラスター化されたU
、X
、および非クラスター化X
ロックが検索と削除の一部として取得されます現在の行に対応するエントリ。
ただし、行がハッシュ結合でしない結合しない場合、U
ロックは解放されません。結合されていない行のU
ロックは、現在のステートメントが終了したときにすべて解放されるまで蓄積され続けます。これは単に、1つの演算子(非クラスター化インデックススキャン)でU
ロックが取得された結果ですが、別の演算子(ハッシュ結合)での適格性がテストされています。
とにかく、複数のU
ロックは、報告されたデッドロックを可能にします。
もちろん、同じネストされたループの計画は、同じデータを処理するときにデッドロックになる可能性もあります(ロックは、より明らかに循環型デッドロックになります)。デッドロックを回避するには、入力セットが互いに素であるか、各セットの行が厳密に同じ順序で処理される(同じ方法でソートされ、実行プランによって同じ順序で処理される)必要があります。
各セッションは、セカンダリインデックスの値に基づいて、同じテーブルから複数の行を削除しています。複数のセッションで同じ行を削除しようとしない場合でも、セッションはセカンダリインデックスを使用して削除する行を検索し、Uロックで読み取り、各行のXロックに変換します。これにより、デッドロックが発生する可能性があります。
Uロックなしで削除する行を検索し、それらを別のステートメントで削除することで、これを回避できます。最初のクエリで見つかった行の一部は、2番目のクエリを試行するまでに削除される場合があります。しかし、あなたはおそらくそれを気にしません。
だから次のようなもの:
declare @ids_to_delete table(id int)
insert into @ids_to_delete(id)
select id
from [model].[AttributeValueHyperlink] AVH
INNER JOIN @AttributeValueIdsTable AVT
ON
[AVT].EntityId = [AVH].AttributeValueI
delete from [model].[AttributeValueHyperlink]
where id in (select id from @ids_to_delete)