SQL Server 2008 R2のデッドロックの問題(.NET 2.0アプリケーション)
-
03-10-2019 - |
質問
問題のSQL Server 2008 R2インスタンスは、重い負荷OLTP生産サーバーです。デッドロックの問題は数日前に現れ、まだ解決されていません。デッドロックに含まれるストアドプロシージャやその他の詳細をリストしたXMLデッドロックレポートを受け取りました。最初にこのXMLからの事実をリストアップしようとします。
SP1とSP2など、2つのストアドプロシージャがデッドロックに関与しています。報告書によると SP1は単独レベルで「シリアル化可能」で実行されていました と SP2は「読み取り」で実行されていました.
以下を調査しました。
SP1のIsolationLevelをSP内またはコード内の「シリアル化可能」に設定していますか? - いいえ。
IsolationLevelがSP1を呼び出す「シリアル化可能」である他のSPはありますか? - いいえ。
SP1が使用するテーブルは、分離レベルを「シリアル化可能」と呼ぶ他のSPによって呼び出されますか? - はい。分離レベルが「シリアル化可能」に設定され、SP1と同じテーブルにアクセスするSPSがありますが、デッドロックの時点で実行されていたかどうかはわかりません。
レポートはSP1とSP2のみを示しました。
思考の線:
次の考えられる原因を検討しました。
SP1が「シリアル化可能」として実行されているため、デッドロックが発生しています。 - なぜこのSPが設定していないときにシリアル化可能であるのですか?分離レベルはエスカレートしていますか(ロックのように)?これを理解し、読み物として実行すると、問題は解決されますか?
他のSPが実行されており、SP1が使用するテーブルをロックし、SP1とSP2の間にデッドロックを引き起こします。 - これはデッドロックレポートにリストされていませんか?デッドロックレポートはそのような依存を逃すことができますか?はいの場合、部分的な情報のみを取得する可能性があります。ただし、SP1がSerializableでどのように実行されているかはまだ解決しません。
提案:
この情報が問題を解決するのに十分でない場合、自分の目的のためにSQL Serverからより多くの情報を取得するにはどうすればよいですか?
この問題を解決する際にあなたが追求する他の考え方はありますか?
アップデート:
これは ログ情報をトレースします デッドロックのために。 SPSなどの名前を変更しましたが、変更が関連情報を見逃さないことを確認して確認しました。テーブルなどの詳細については、コードに続くメモを確認してください。
?<EVENT_INSTANCE>
<EventType>DEADLOCK_GRAPH</EventType>
<PostTime>2010-09-07T11:27:47.870</PostTime>
<SPID>16</SPID>
<TextData>
<deadlock-list>
<deadlock victim="process5827708">
<process-list>
<process id="process5827708" taskpriority="0" logused="0" waitresource="KEY: 7:72057594228441088 (8d008a861f4f)"
waittime="5190" ownerId="1661518243" transactionname="SELECT" lasttranstarted="2010-09-07T11:27:42.657"
XDES="0x80bf3b50" lockMode="RangeS-S" schedulerid="4" kpid="2228" status="suspended" spid="76" sbid="0"
ecid="0" priority="0" trancount="0" lastbatchstarted="2010-09-07T11:27:42.657"
lastbatchcompleted="2010-09-07T11:27:42.657" clientapp=".Net SqlClient Data Provider"
hostname="xxx" hostpid="5988" loginname="xxx" isolationlevel="serializable (4)"
xactid="1661518243" currentdb="7" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="SP1" line="12" stmtstart="450" stmtend="6536"
sqlhandle="0x0300070090cbdc7742720c00e99d00000100000000000000">
Select ... from Table1, Table2, Table4, Table5
</frame>
</executionStack>
<inputbuf>
Proc [Database Id = 7 Object Id = 2010958736]
</inputbuf>
</process>
<process id="process5844bc8" taskpriority="0" logused="1873648" waitresource="KEY: 7:72057594228441088 (0e00ce038ed0)"
waittime="4514" ownerId="1661509575" transactionname="user_transaction" lasttranstarted="2010-09-07T11:27:40.423"
XDES="0x37979ae90" lockMode="X" schedulerid="7" kpid="3260" status="suspended" spid="104" sbid="0" ecid="0"
priority="0" trancount="2" lastbatchstarted="2010-09-07T11:27:43.350" lastbatchcompleted="2010-09-07T11:27:43.350"
clientapp=".Net SqlClient Data Provider" hostname="xxx" hostpid="5988" loginname="xxx"
isolationlevel="read committed (2)" xactid="1661509575" currentdb="7" lockTimeout="4294967295"
clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="SP2" line="68" stmtstart="5272" stmtend="5598"
sqlhandle="0x030007003432350f109a0c00e99d00000100000000000000">
UPDATE Table1 ...
</frame>
</executionStack>
<inputbuf>
Proc [Database Id = 7 Object Id = 255144500]
</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594228441088" dbid="7" objectname="Table1" indexname="Index1"
id="lock448e2c580" mode="X" associatedObjectId="72057594228441088">
<owner-list>
<owner id="process5844bc8" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process5827708" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594228441088" dbid="7" objectname="Table1" indexname="Index1"
id="lock2ba335880" mode="RangeS-S" associatedObjectId="72057594228441088">
<owner-list>
<owner id="process5827708" mode="RangeS-S" />
</owner-list>
<waiter-list>
<waiter id="process5844bc8" mode="X" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>
</TextData>
<TransactionID />
<LoginName>xx</LoginName>
<StartTime>2010-09-07T11:27:47.867</StartTime>
<ServerName>xxx</ServerName>
<LoginSid>xxx</LoginSid>
<EventSequence>116538375</EventSequence>
<IsSystem>1</IsSystem>
<SessionLoginName />
</EVENT_INSTANCE>
SP1は、5つの異なるテーブル(Table1からTable5)のデータを取得する選択を実行しています(内側クエリなどを使用)SP2はTable1で更新を実行します。
興味深いのは、SP2の更新がTable1の外部キーフィールドであり、Table2の主要なキーであり、Table1とTable2の両方がSP1のSelectステートメントの一部であるという列の1つですが、これが関連性があるかどうかはわかりませんが、見逃したくありませんでした。なんでも。
注:indexName = "index1"(上記のデッドロックグラフ) - index1は、表1の外部キーであり、表2の主キーである同じ列にあります。
解決
これをチェックして MSDNの記事 どの州:
分離レベルには接続全体のスコープがあり、一度設定されたトランザクション分離レベルステートメントとの接続に設定されると、接続が閉じられるか、別の分離レベルが設定されるまで有効になります。接続が閉じてプールに戻ると、最後のセットトランザクション分離レベルのステートメントからの分離レベルが保持されます。プールされた接続を再利用するその後の接続は、接続がプールされた時点で有効だった分離レベルを使用します。
問題は、シリアル化可能な分離レベルで接続が開かれることでした。関連するトランザクションは処分されたため、接続も同様でしたが、接続は破壊されず、接続プールに移動しました。次回、接続の要求が(同じ接続文字列を使用して)行われたとき、この接続は返され、クエリは分離レベルを指定しなかったため、シリアル化可能な分離レベルで実行されていました。
基本的に、接続プールがあり、特定の分離レベルで接続を開く場合、シリアル化可能な場合、接続は分離レベルがシリアル化可能に設定されてプールに戻ります。次回接続を要求するときは、この接続が返されないことを確認できないため、デフォルトの分離レベルを介して読み込まれていても、これらの「シリアル化可能な」接続のいずれかを取得できます。
別の警告は、分離レベルをシリアル化可能な(またはその他のもの)に設定するたびに、さまざまな接続を選択し、ゆっくりと接続プールの接続をより多くの接続を汚染する可能性があることです。あなたが設定した)。
廃棄接続をリセットするメカニズムは見つかりませんでした(クエリを実行した後に接続プールに戻ったとき)。 1つの回避策は、各接続の分離レベルを明示的にリセットすることです。しかし、これは退屈です。
したがって、最良の選択肢は、異なる分離レベルのために個別の接続プールを作成することです.
他のヒント
SP1で選択したテーブルの後に(nolock)を追加して、これらの特定のテーブルに読み取りロックを追加できないようにします。
状況によっては、クラスター化されていないインデックスが間にデッドロックを引き起こす可能性があることを知っています SELECT
と UPDATE
声明、そしてあなたの場合にこれが関連するかもしれないように聞こえます。詳細については、これらのリンクを参照してください。
- 非クラスター化されたインデックスを備えたSQL Server 2005デッドロック
- INF:SQL Serverのデッドロックの分析と回避 特に 例6:クラスター化されていないインデックス