デッドロックの原因となっている 2 つのクエリは、SELECT
です。 以下 (process id="process3980de4558"
):
select @existing = team_it_cube_attr_05 from tbl_Ref_Attr_Prod_Team where prod_id = @rec_key
プレ>そして
UPDATE
以下のクエリ (process id="process386ed48188"
):UPDATE D SET D.team_rss_attr_01 = LEFT(S.mkt_prodchar_13,25)...
プレ>
<resource-list>
セクションはSELECT
に注意します クエリがページの排他 (X) ロックを所有しており、データの読み取り中に別のページでインテント共有 (IS) ロックを取得しようとしていました。UPDATE
クエリは既に IS ロックを所有しており、更新を実行するためにページで X ロックを取得しようとしました。このテーブルに対する結合を考えると:
...from tbl_Ref_Attr_Prod_Team where prod_id = @rec_key... ...INNER JOIN tbl_Ref_Attr_Prod_Team D ON D.prod_key=P.prod_key...
プレ>
SELECT
クエリはすでに排他ロックを所有しています。これはおそらく、すでにUPDATE
を実行した大きなトランザクションの一部であることを意味します 以前のクエリで。以前のクエリからのロックは、トランザクション中にデータの整合性を維持するために維持されます (トランザクション分離レベル ).
UPDATE
クエリはテーブルtbl_Ref_Attr_Prod_team
を読み取る必要があります .データの読み取り中に、ページと行でインテント共有ロックを取得します。UPDATE
クエリが一致する行を見つけると、IS ロックを X ロックに変換しようとします。 IS ロックは X ロックと互換性がありません。SELECT
クエリは、これらのページの 1 つ以上で既に IS ロックを持っており、クエリは互いにデッドロックしています。考えられる原因の 1 つは、
tbl_Ref_Attr_Prod_team.prod_key
にインデックスがないことです。 .この列にインデックスがないと、UPDATE
クエリは、テーブルtbl_Ref_Attr_Prod_team
内のすべての行をスキャンします .
prod_key
にインデックスが存在する場合でも 、テーブルに少数の行がある場合、SQL Server は、クエリがインデックスをシークする代わりにテーブル全体をスキャンした方がパフォーマンスが向上すると判断する場合があります。デッドロックが発生したときにクエリ プランを記録すると、この理論が検証されます。新しいデータベースをステージングするときに、小さなテーブルのデッドロックが定期的に発生します。最初は、テーブルは小さく、テーブル スキャンはあらゆる種類のデッドロックを引き起こします。その後、テーブルが大きくなると、計算されたテーブル スキャンのコストがインデックスのシーク コストを上回り、デッドロックは発生しなくなります。行数が非常に少ないテスト環境では、
FORESEEK
を使用することに頼りました。 およびWITH INDEX
スキャンの代わりにインデックスシークを強制するヒント。 SQL Server 2016 のクエリ ストア機能を介してクエリ プランを強制できることを楽しみにしています。