SQL Server 2008 R2中的死锁问题(.Net 2.0应用程序)

有问题的Sql Server 2008 R2实例是重负载的OLTP生产服务器。 这个僵局问题几天前就出现了,但仍然没有解决。 我们收到了列出涉及死锁的存储过程和其他一些细节的Xml死锁报告。 我会尝试从这个XML首先列出事实:

两个存储过程涉及到死锁,比如SP1和SP2。 根据报告, SP1在隔离级别“Serializable” 中运行,SP2在“ReadCommitted”中运行

我们已经调查了以下内容:

  • 我们是否将SP1的IsolationLevel设置为SP或代码中的“Serializable”? - 没有

  • 其他IsolationLevel是“Serializable”调用SP1的其他SP? - 没有

  • SP使用的表是否由隔离级别为“可序列化”的其他任何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执行一个从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(或者其他任何类型)来污染连接池中越来越多的连接你设定)。

    我没有找到任何机制来重置处置连接(当它执行我的查询后返回到连接池)。 一种解决方法是显式重置每个连接的隔离级别。 但这很乏味。

    所以最好的选择是为不同的隔离级别创建单独的连接池


    在sp1中的那些选定表格之后添加(nolock)以确保无法将读取锁定添加到这些特定表格。


    我知道在某些情况下,非聚集索引会导致SELECTUPDATE语句之间的死锁,听起来这可能与您的情况有关。 请参阅以下链接了解更多信息:

  • 带非聚簇索引的SQL Server 2005死锁
  • INF:分析和避免SQL Server中的死锁特别是示例6:非聚簇索引
  • 链接地址: http://www.djcxy.com/p/2803.html

    上一篇: Deadlock issue in SQL Server 2008 R2 (.Net 2.0 Application)

    下一篇: Ruby, get hours, seconds and time from Date.day