7

問題のSqlServer2008 R2インスタンスは、高負荷のOLTP本番サーバーです。デッドロックの問題は数日前に発生しましたが、まだ解決されていません。デッドロックに関連するストアドプロシージャとその他の詳細をリストしたXmlデッドロックレポートを受け取りました。最初に、このxmlから事実をリストアップしようとします。

デッドロックには、SP1とSP2の2つのストアドプロシージャが関係しています。レポートによると、SP1は分離レベル「Serializable」で実行され、SP2は「ReadCommitted」で実行されていました

以下を調査しました。

  • SP内またはコードでSP1のIsolationLevelを「Serializable」に設定していますか?- いいえ。

  • IsolationLevelが「Serializable」である他のSPはSP1を呼び出していますか?- いいえ。

  • SP1で使用されるテーブルは、分離レベルが「シリアル化可能」である他のSPによって呼び出されますか?- はい。
    分離レベルが「シリアル化可能」に設定され、SP1と同じテーブルにアクセスするSPがありますが、デッドロックレポートにはSP1とSP2しか表示されていないため、デッドロック時に実行されていたかどうかはわかりません。

考え方:
次の考えられる原因を検討しました。

  • SP1が「シリアル化可能」として実行されているため、デッドロックが発生しています。-設定していないのに、なぜこのSPがSerializableで実行されているのですか?分離レベルは(ロックのように)エスカレートしていますか?これを理解してReadCommittedとして実行すると、問題は解決しますか?

  • 他のSPが実行されており、SP1が使用するテーブルがロックされ、SP1とSP2の間にデッドロックが発生します。-このSPはデッドロックレポートにリストされませんか?デッドロックレポートはそのような依存関係を見逃す可能性がありますか?はいの場合、部分的な情報しか取得していない可能性があります。ただし、これでもSP1がSerializableでどのように実行されているかは解決されません。

提案:

  • この情報が問題の解決に十分でない場合、自分の目的のためにSQL Serverからより多くの情報を取得するにはどうすればよいですか?また、どのような情報を収集する必要がありますか?

  • この問題を解決するために追求する他の考え方はありますか?

更新:
これは、デッドロックのトレースログ情報です。SP等の名称を変更しましたが、関連情報を見逃していないことを確認・確認しました。テーブルなどの詳細については、コードに続くメモを確認してください。

?<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が更新する列の1つが、Table1の外部キーフィールドとTable2の主キーであり、Table1とTable2の両方がSP1のselectステートメントの一部であるということです。これが適切かどうかはわかりませんが、見逃したくありませんでした。なんでも。

注:indexname = "Index1"(上記のデッドロックグラフ内)-Index1は、Table1の外部キーおよびTable2の主キーと同じ列にあります。

4

3 に答える 3

2

次のMSDN の記事を確認してください。

分離レベルには接続全体のスコープがあり、SET TRANSACTION ISOLATION LEVEL ステートメントを使用して接続に対して設定されると、接続が閉じられるか別の分離レベルが設定されるまで有効です。接続が閉じられてプールに戻されると、最後の SET TRANSACTION ISOLATION LEVEL ステートメントからの分離レベルが保持されます。プールされた接続を再利用する後続の接続では、接続がプールされた時点で有効だった分離レベルが使用されます。

問題は、Serializable 分離​​レベルで接続が開かれることでした。関連するトランザクションは破棄され、接続も破棄されましたが、接続は破棄されず、接続プールに移動しました。次に接続のリクエストが(同じ接続文字列で)行われたとき、この接続が返され、クエリで分離レベルが指定されていなかったため、Serializable 分離​​レベルで実行されていました。

基本的に、接続プールがあり、特定の分離レベル (Serializable など) で接続を開くと、分離レベルが Serializable に設定された状態で接続がプールに戻ります。次回接続を要求するときに、この接続が返されないことを確認できないため、デフォルトの分離レベルが ReadCommitted であっても、これらの「シリアル化可能な」接続のいずれかを取得する可能性があります。

もう1つの注意点は、分離レベルをSerializable(またはその他のもの)に設定するたびに、異なる接続を選択している可能性があり、分離レベルをSerializable(またはその他のもの)に設定することで、接続プール内の接続を徐々に汚染する可能性があることです。あなたが設定した)。

破棄中の接続をリセットするメカニズムが見つかりませんでした (クエリの実行後に接続プールに戻ったとき)。1 つの回避策は、各接続の分離レベルを明示的にリセットすることです。しかし、これは面倒です。

したがって、最適な代替手段は、分離レベルごとに個別の接続プールを作成することです。

于 2012-04-02T09:47:10.557 に答える
1

sp1 で選択したテーブルの後に with(nolock) を追加して、これらの特定のテーブルに読み取りロックを追加できないようにします。

于 2011-04-08T06:27:26.200 に答える
0

状況によっては、非クラスター化インデックスがステートメントSELECTUPDATEステートメントの間でデッドロックを引き起こす可能性があることを私は知っています。詳細については、次のリンクを参照してください。

于 2011-04-10T04:12:24.683 に答える