web-dev-qa-db-ja.com

SELECTでパーティション化された列ストアのデッドロックを防ぐ方法

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)は、別のプロセスを使用する一般的な待機可能オブジェクトリソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行します。

手がかり:

  • クエリがCCI以外の別のインデックスを使用する場合、デッドロックは発生しません。
  • 3つのテナントフィルターのうち2つを削除しても、デッドロックしません。
  • トップ32以下を選択しても、デッドロックは発生しません。
  • OPTION(MAXDOP 1)を追加しても、デッドロックは発生しません。
  • これをスクランブル処理されたPRODレプリカ、PROD読み取り専用セカンダリ、およびPROD自体で再現できます。
  • この動作をDEVまたはINTで再現できません。
  • 3つのテーブル結合すべてにWITH(NOLOCK)を追加すると、依然としてデッドロックが発生します
  • クエリ自体がデッドロックします。他にアクティブなプロセスがない場合はデッドロックします。
  • 並列処理のないクエリプランはデッドロックしない

Deadlock xml here

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 :)(ハイパーバイザー)

このクエリのデッドロックを防ぐにはどうすればよいですか?

10
Cyndi Baker

SQL Server 2016を使用しているので、列ストアインデックスに関連する並列デッドロックの少なくとも1つのパブリックバグ修正があることを言及する価値があります。

FIX:SQL Server 2016および2017でクラスター化列ストアインデックスに対して並列クエリを実行すると、デッドロックが発生します

(ありがとう Denis Rubashkin 最初にリンクを提供してくれたことに感謝)

これはSP1 CU7の一部としてリリースされました。そのCUに達していない場合は、試してみてください。この修正はSP2(いずれかのCU)にも含まれます。

一般に、クエリ内並列処理のデッドロックを修正するための2つのアプローチ:

  • 並列処理を回避する(MAXDOPヒントを使用するなど、クエリが並列にならないように調整する)-これは other answerThomas Costers
  • sQL Serverに最新のサービスパック/累積的な更新を適用する
8
Josh Darnell

Intra-Query Parallel Thread Deadlocks で次のブログを確認しましたか?

SyncPointリソースは、私が誤解していない場合の交換イベントの使用を示しています。
デッドロックの参加者を見ると、それらはすべて同じspid(55)とbatch(0)からのものであるが、異なるスレッドを使用していることがわかります。これは、それらがすべて同じ並列クエリの一部であることを示しており、MAXDOP 1を使用してクエリを実行するたびにデッドロックが発生しないという事実によって確認されています。クエリ内並列スレッドデッドロックの場合、単一のクエリのスレッドは、最終的に同期オブジェクト(この場合はSyncPoints)を待機して互いにデッドロックします。

この種の動作を最後に目にしたとき、クエリをさらに最適化して、クエリが並列実行プランを使用するのを防ぐことができました。結果セットを32レコードに制限するか、別のインデックスを使用して、同じことをしたと思います。
別のオプションは、クエリにMAXDOP 1を追加することですが、このオプションの大ファンではありません。

ただし、これら2つのオプションをいじる前に、まず最新のSP/CUを使用しているかどうかを確認してください。

2
Thomas Costers