簡體   English   中英

SQL Server 2008 R2中的死鎖問題(.Net 2.0應用程序)

[英]Deadlock issue in SQL Server 2008 R2 (.Net 2.0 Application)

有問題的Sql Server 2008 R2實例是一個重負載OLTP生產服務器。 幾天前出現了死鎖問題,但仍未解決。 我們收到了Xml死鎖報告,其中列出了死鎖中涉及的存儲過程以及其他一些細節。 我將首先嘗試從這個xml中列出事實:

死鎖涉及兩個存儲過程,例如SP1和SP2。 根據報告, SP1在隔離級別“Serializable” 中運行,SP2在“ReadCommitted”中運行

我們調查了以下內容:

  • 我們在SP或代碼中將IsolationLevel SP1設置為“Serializable”嗎? - 沒有。

  • 是否其他SP的IsolationLevel是“Serializable”調用SP1? - 沒有。

  • SP1使用的表是否被隔離級別為“可序列化”的任何其他SP調用? - 是的 有些SP將隔離級別設置為“可序列化”並訪問與SP1相同的表,但我們不知道它們是否在死鎖時運行,因為死鎖
    報告僅顯示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正在執行一個select,它從5個不同的表(Table1到Table5)中獲取數據(使用內部查詢等).SP2對Table1執行更新。
一個有趣的事情是SP2更新的一列是Table1中的外鍵字段和Table2的主鍵,而Table1和Table2都是SP1的select語句的一部分,不確定這是否相關但不想錯過任何東西。

注意:indexname =“Index1”(在上面的死鎖圖中) - Index1與Table1中的外鍵和Table2的主鍵位於同一列上。

查看此MSDN文章 ,其中說明:

隔離級別具有連接范圍范圍,並且一旦設置為與SET TRANSACTION ISOLATION LEVEL語句的連接,它將保持有效,直到連接關閉或設置了另一個隔離級別。 關閉連接並返回到池時,將保留最后一個SET TRANSACTION ISOLATION LEVEL語句的隔離級別。 重新使用池連接的后續連接使用在連接池時生效的隔離級別。

問題是連接以Serializable隔離級別打開; 關聯的事務已被處置,連接也是如此,但連接沒有被銷毀並進入連接池。 下次發生連接請求(使用相同的連接字符串)時,會返回此連接,並且由於查詢未指定任何隔離級別,因此它在Serializable隔離級別執行。

基本上,如果你有一個連接池並在特定的隔離級別打開一個連接,讓我們說Serializable,那么連接將返回到池,隔離級別設置為Serializable。 下次請求連接時,您無法確定是否會返回此連接,因此即使通過默認隔離級別進行ReadCommitted,您也可能會獲得這些“Serializable”連接之一。

另一個需要注意的是,每次將隔離級別設置為Serializable(或其他任何內容)時,您可能會選擇不同的連接,並且通過將其隔離級別設置為Serializable(或其他任何內容),您可能會慢慢污染連接池中的越來越多的連接。你設定)。

我沒有找到任何機制來重置配置連接(當它在執行我的查詢后返回連接池時)。 一種解決方法是顯式重置每個連接的隔離級別。 但這很乏味。

因此,最好的替代方法是為不同的隔離級別創建單獨的連接池

在sp1中的那些選定表之后添加(nolock)以確保無法向這些特定表添加讀鎖定。

我知道在某些情況下,非聚簇索引會導致SELECTUPDATE語句之間出現死鎖,聽起來這可能與您的情況有關。 有關更多信息,請參閱以下鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM