SELECT / INSERTデッドロック


10

このインスタンスは、SharePoint 2007データベース(SP)をホストします。SPコンテンツデータベース内の使用率の高い1つのテーブルに対して、多数のSELECT / INSERTデッドロックが発生しています。関連するリソースを絞り込みました。両方のプロセスで非クラスター化インデックスのロックが必要です。
INSERTはSELECTリソースでIXロックを必要とし、SELECTはINSERTリソースでSロックを必要とします。デッドロックグラフは、3つのリソースを示しています。1)SELECT(プロデューサー/コンシューマーパラレルスレッド)からの2つ、および2)INSERTです。
確認のためにデッドロックグラフを添付しました。これはMicrosoftのコードとテーブルの構造であるため、変更を加えることはできません。
ただし、MSFT SPサイトで、MAXDOPインスタンスレベルの構成オプションを1に設定することを推奨していることを確認しました。このインスタンスは他の多くのデータベース/アプリケーション間で共有されているため、この設定を無効にすることはできません。


したがって、私はこれらのSELECTステートメントが並列にならないようにすることを試みました。これは解決策ではなく、トラブルシューティングに役立つ一時的な変更であることがわかっています。そのため、ワークロードが変更されていない(SELECT / INSERTが頻繁に発生する)にもかかわらず、デッドロックがなくなったにもかかわらず、「並列処理のコストしきい値」を標準の25から40に増やしました。私の質問はなぜですか?

SPID 356 INSERTは、非クラスター化インデックスに属するページにIXロックを持っています
SPID 690 SELECT実行ID 0は、同じ非クラスター化インデックスに属するページにSロックを持っています

SPID 356はSPID 690リソースのIXロックを要求しますが、SPID 690がSPID 690によってブロックされているため、それを維持
できません。 1はSPID 356によってブロックされており、デッドロックが発生しています。

実行計画は私のSkyDriveにあります

完全なデッドロックの詳細はここにあります

誰かが私になぜそれを本当に感謝するか理解するのを手伝ってくれるなら。

EventReceiversテーブル。
Id uniqueidentifier no 16
Name nvarchar no 512
SiteId uniqueidentifier no 16
WebId uniqueidentifier no 16
HostId uniqueidentifier no 16
HostType
int no 4
ItemId int no 4 DirName nvarchar no 512
LeafName nvarchar no 256
Type int no 4
SequenceNumber int no 4
Assembly nvarchar no 512
Class nvarcharいいえ512
データnvarcharいいえ512
フィルターnvarcharいいえ512
SourceId tContentTypeIdいいえ512
SourceType int no 4
Credential int no 4
ContextType varbinary no 16
ContextEventType varbinary×16
ContextId varbinary
× 16 ContextObjectId varbinary×16
ContextCollectionId varbinary × 16

index_name index_description index_keys
EventReceivers_ByContextCollectionId非クラスター化はPRIMARY SiteIdにあり、ContextCollectionId
EventReceivers_ByContextObjectId非クラスター化はPRIMARY SiteIdにあり、ContextObjectId
EventReceivers_ById非クラスター
化は、PRIMARY SiteIdにあります。 ContextId、ContextType、ContextEventType、SequenceNumber、Assembly、Class
EventReceivers_IdUnique非クラスター化、一意、PRIMARY Idにある一意のキー


2
何をするproc_InsertEventReceiverと、proc_InsertContextEventReceiver私たちはXDLで見ることができないのですか?また、並列処理を減らすために、サーバー全体の設定でファッツするのではなく、これらのステートメントに直接(MAXDOP 1を使用して)影響を与えるだけではないのですか?
アーロンバートランド

1
MAXDOPのサーバー設定の幅と、プロセッサー(論理)の数を知りたいです。SharePointは実際にはうまく機能し、MAXDOPサーバー幅が1.のサーバー上に配置することを好みます。実際の実行計画を投稿できますか?そのリンクで私が見るすべては.xdl(デッドロックグラフ)です
Mike Walsh

こんにちは紳士私はあなたの忙しいスケジュールから応答するために時間を割いていただき本当にありがとうございます。確認のための手順と実行計画の両方をSkyDriveサイトに投稿します。クエリオプションMAXDOP(1)を含むようにコードを変更することを考えていましたが、変更するとMicrosoftのサポートが無効になります。物理サーバーはProLiant DL580 G4で、MAXDOP設定は4で、合計8つの物理プロセッサーがあり、H / Tは無効になっています。
SQLJarHead

皆さん、こんにちは。SkyDriveのすべての詳細を含むzipパッケージを作成しました。元の投稿の本文を変更して、パッケージのURLを含めました。何が問題なのか教えないでください。ガイダンスを提供して、私に問題を解決してもらいます。注:基になるスキーマにコードの変更やDDLの変更を加えることはできません。
SQLJarHead

1
したがって、コードを変更したり、スキーマを変更したりすることはできません。他にどのようなソリューションが考えられますか?マイクロソフトのサポートを無効にすることについて心配している場合、それはあなたマイクロソフトのサポートを持っていることを意味します。
アーロンバートランド

回答:


14

一見すると、これは古典的なルックアップデッドロックのように見えます。このデッドロックパターンに不可欠な要素は次のとおりです。

  • SELECTキールックアップで非カバリング非クラスター化インデックスを使用するクエリ
  • INSERTクラスタ化インデックス、その後、非クラスタ化インデックスを変更するクエリ

SELECT最初に非クラスター化インデックスにアクセスし、次にクラスター化インデックスにアクセスします。INSERTアクセスクラスタ化インデックス最初に、その後、非クラスタ化インデックス。もちろん、同じリソースに異なる順序でアクセスして互換性のないロックを取得することは、もちろんデッドロックを「達成する」ための優れた方法です。

この場合、SELECTクエリは次のとおりです。

SELECTクエリ

...そしてINSERTクエリは:

クエリの挿入

緑で強調表示された非クラスター化インデックスのメンテナンスに注意してください。

SELECTプランのシリアルバージョンがパラレルバージョンと非常に異なる場合は、プランのシリアルバージョンを確認する必要がありますが、ジョナサンケハイアスがデッドロックの処理に関するガイドで指摘しているように、この特定のデッドロックパターンは、タイミングと内部クエリ実行の実装の詳細に非常に敏感です。このタイプのデッドロックは、明らかな外部の理由なしにしばしば行き来します。

関連するシステムへのアクセスと適切な権限があれば、最終的に並列計画でデッドロックが発生するのに、シリアルではなくなぜデッドロックが発生するのかを正確に突き止めることができると確信しています(同じ一般的な形を想定しています)。潜在的な問い合わせ行には、最適化されたネストされたループのチェックやプリフェッチなどが含まれます-どちらも、ステートメントの期間中、内部的に分離レベルエスカレートできREPEATABLE READます。並列インデックスシーク範囲の割り当ての一部の機能が問題の原因である可能性もあります。シリアルプランが利用可能になった場合は、興味を引く可能性があるため、詳細をさらに調査することに少し時間をかけることがあります。

このタイプのデッドロックの通常の解決策は、インデックスをカバーすることですが、この場合の列の数はそれを非現実的にする可能性があります(それに加えて、SharePointでそのようなことを混乱させることは想定されていません)。結局のところ、SharePointを使用する場合のシリアルのみのプランの推奨は、理由があります(それには、必ずしも適切なものではありませんが)。並列処理のコストしきい値の変更により、現時点で問題が修正されている場合、これは問題ありません。長期的には、おそらくリソースガバナーを使用してワークロードを分離し、SharePointの内部クエリで目的のMAXDOP 1動作が得られ、他のアプリケーションで並列処理を使用できるようにすることを検討します。

デッドロックの痕跡に現れる交換の問題は、私にとっては赤いニシンのようです。技術的にツリーに表示されなければならないリソースを所有する独立したスレッドの単なる結果。交換自体がデッドロックの問題に直接貢献していることを示唆するものは何もありません。


6

これが従来のルックアップデッドロックであった場合、リソースリストにはクラスター化インデックスと非クラスター化インデックスの両方が含まれます。通常、SELECTはNCインデックスのSHAREDロックを保持し、CIのSHAREDロックを待ちますが、INSERTはCIのEXCLUSIVEロックを取得して、NCのEXCLUSIVEロックを待ちます。この場合、デッドロックxmlのリソースリストには、これらの両方のオブジェクトがリストされます。

デッドロックグラフにはNCインデックスのみが含まれるため、そのオプションを除外できます。

また、これがUNORDERED PREFETCHでのネストされたループ結合によるデッドロックであった場合、実行プランはUNORDERED PREFETCHアルゴリズムが使用されているかどうかを通知しますが、これはここでは当てはまりません(以下の更新を参照)。

そのため、これは並列プランによるデッドロックであると想定する必要があります。

デッドロックグラフは適切にレンダリングされませんが、デッドロックXMLを見ると、SELECTステートメント(SPID 690)からの2つのスレッドがデッドロックに関係していることがわかります。コンシューマスレッドは、ページ1219645で共有ロックを保持し、ポート801f8ed0(e_waitPipeGetRow)でプロデューサを待機しています。プロデューサスレッドは、ページ1155940で共有ロックを待機しています。

INSERTステートメントは、ページ1155940でIXロックを保持しており、ページ1219645でIXロックを待機しているため、デッドロックが発生しています。

SELECTステートメントにシリアルプランを使用すると、複数のページでSHAREDロックを必要としないため、デッドロックが回避されると思います。また、シリアルプランはパラレルプランとほぼ同じになると思います(並列化演算子を除きます)。

[ポールのコメントに基づいて更新]

どうやら計画はOPTIMIZEDネストループアルゴリズムを使用しています

これが、SHAREDロックがステートメントの終わりまで保持される理由を説明しています。パラレルプランと組み合わせてREPEATABLE READを実行すると、シリアルプランよりもデッドロックの影響を受けやすくなります。これは、パラレルプランがインデックスの異なる範囲からロックを取得して保持するのに対し、シリアルプランはより順次的な方法でロックを取得するためです。


同意した。このデッドロックが実際のLOOKUPに関連している場合、SELECTの待機リソースはクラスター化インデックスを参照していました。DBCC PAGEを介して各待機リソース(SPID 690待機リソース= PAGE:1155940 | SPID 356待機リソース= PAGE 1219645)のページヘッダーを表示し、両方がインデックスID 5(IndexID 5 = EventReceivers_ByContextObjectId)にあったことを除外できました指定されたテーブル(EventReceivers)のNCインデックスを指します。
SQLJarHead

皆さん、この興味深い問題の分析にご協力いただき、ありがとうございました。いくつかの質問:1.)Rojiは、並列SPIDが複数のページを要求していると指摘しています。実行計画のどれにもそれはありません。行の数を見ると、INDEX SEEK演算子の場合、2つのプロデューサーのうち1つのスレッドのみが行を処理しています。複数のページをリクエストしているとどのように判断しましたか?(1/2)
SQLJarHead

2.)OPTIMIZED Nested Loopアルゴリズムは常に分離レベルをREAPTABLE READに設定しますか?実行プランのXML出力を確認しましたが、SPID接続に対してコミットされた読み取りのみが表示されます。私は、これはプランオペレーターレベルでのみ呼び出されると仮定しています。(2/2)
SQLJarHead

OPTIMIZED Nested Loopsのロック動作はREPEATABLE READに相当します(ステートメントの終わりまでロックを保持します)が、トランザクションの分離レベルをREPEATABLE READに明示的に設定しません。それもあなたの質問の一つに答えると思います。並列スレッドが一度に複数のページを要求しているわけではありませんが、1つの並列スレッドが1つのページのロックを保持し、別のスレッドが別のページのロックを待機しています
Roji P Thomas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.