SQL Server 2016に3つのクラスター化列ストアインデックス(CCI)テーブルがあります。これらのCCIはすべて、テナントIDに基づいて同じパーティションスキームにあります。最近、一貫性のない方法で、これらのテーブルへの結合からの単純な選択ステートメントでデッドロックが発生しています。デッドロックするクエリの例:
SELECT TOP 33 r.tenantid
FROM Table_r r
INNER JOIN Table_cm cm ON r.MyKey=cm.MyKey
INNER JOIN Table_pe pe ON r.MyKey=pe.MyKey
WHERE r.TenantId = 69
AND pe.TenantId = 69
AND cm.TenantId = 69
エラーメッセージ:
トランザクション(プロセスID 56)は、別のプロセスを使用する一般的な待機可能オブジェクトリソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行します。
手がかり:
PRODバージョン:
Microsoft SQL Server 2016(SP2-CU5)(KB4475776)-13.0.5264.1(X64)Jan 10 2019 18:51:38 Copyright(c)Microsoft Corporation Enterprise Edition(64-bit)on Windows Server 2012 R2 Standard 6.3(Build 9600 :)(ハイパーバイザー)
このクエリのデッドロックを防ぐにはどうすればよいですか?
SQL Server 2016を使用しているので、列ストアインデックスに関連する並列デッドロックの少なくとも1つのパブリックバグ修正があることを言及する価値があります。
FIX:SQL Server 2016および2017でクラスター化列ストアインデックスに対して並列クエリを実行すると、デッドロックが発生します
(ありがとう Denis Rubashkin 最初にリンクを提供してくれたことに感謝)
これはSP1 CU7の一部としてリリースされました。そのCUに達していない場合は、試してみてください。この修正はSP2(いずれかのCU)にも含まれます。
一般に、クエリ内並列処理のデッドロックを修正するための2つのアプローチ:
MAXDOP
ヒントを使用するなど、クエリが並列にならないように調整する)-これは other answer で Thomas CostersIntra-Query Parallel Thread Deadlocks で次のブログを確認しましたか?
SyncPoint
リソースは、私が誤解していない場合の交換イベントの使用を示しています。
デッドロックの参加者を見ると、それらはすべて同じspid(55)とbatch(0)からのものであるが、異なるスレッドを使用していることがわかります。これは、それらがすべて同じ並列クエリの一部であることを示しており、MAXDOP 1
を使用してクエリを実行するたびにデッドロックが発生しないという事実によって確認されています。クエリ内並列スレッドデッドロックの場合、単一のクエリのスレッドは、最終的に同期オブジェクト(この場合はSyncPoints)を待機して互いにデッドロックします。
この種の動作を最後に目にしたとき、クエリをさらに最適化して、クエリが並列実行プランを使用するのを防ぐことができました。結果セットを32レコードに制限するか、別のインデックスを使用して、同じことをしたと思います。
別のオプションは、クエリにMAXDOP 1
を追加することですが、このオプションの大ファンではありません。
ただし、これら2つのオプションをいじる前に、まず最新のSP/CUを使用しているかどうかを確認してください。