【问题标题】:Deadlock issue in SQL Server 2008 R2 (.Net 2.0 Application)SQL Server 2008 R2(.Net 2.0 应用程序)中的死锁问题
【发布时间】:2010-09-16 10:38:27
【问题描述】:

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

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

我们调查了以下内容:

  • 我们是否设置了 SP1 的 IsolationLevel 在 SP 或在“可序列化” 代码? - 没有。

  • 是任何其他 SP 的 IsolationLevel 是“可序列化”调用 SP1 吗? - 没有。

  • SP1 使用的表是由 任何其他具有隔离功能的 SP 级别为“可序列化”? - 是的。 有些 SP 具有隔离功能 级别设置为“可序列化”和 访问与 SP1 相同的表, 但我们不知道他们是否 当时正在运行 死锁还是不死锁
    报告仅显示 SP1 和 SP2。

思路:
我们考虑了以下可能的原因:

  • 发生死锁是因为 SP1 是 作为“可序列化”运行。 - 为什么是 这个 SP 运行在 Serializable 时 我没设置?是隔离 级别升级(就像锁一样)?如果 我们解决了这个问题并让它运行为 ReadCommitted,问题会不会是 解决了吗?

  • 任何其他 SP 正在运行,锁定 SP1 使用的表并导致 SP1 和 SP2 之间的死锁。 - 这个SP不会列在 死锁报告?能否陷入僵局 报告错过了这样的依赖?如是 那么我们可能只会得到部分 信息。这个还是不行 解决 SP1 的运行方式 不过可序列化。

建议:

  • 如果此信息不充分 在解决问题时,我该如何 从 SQL 获取更多信息 服务器为我的目的和什么 我应该尝试收集信息吗?

  • 任何其他你想要的思路 追求解决这个问题?

更新:
这是死锁的跟踪日志信息。我已经更改了 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 的主键位于同一列。

【问题讨论】:

  • 首先,您需要提供来自DBCC TRACEON (1222, -1) 的输出以及死锁中涉及的架构位
  • 我有 1222 跟踪但如何使其可用。是否可以上传带有问题的文件,或者我应该将它与问题一起粘贴(真的很大)?
  • 只需抓住几个死锁链并嵌入答案中。然后为事务和相关架构提供 SQL
  • 更新了死锁跟踪和相关架构信息。如果需要更多信息,请告诉我。
  • 隔离级别不会升级。我相信那条道路上的调查不会透露太多信息。但我知道你可以在触发器、子过程,尤其是索引视图的更新上设置可序列化的隔离级别。

标签: sql-server database sql-server-2008 deadlock sql-server-2008-r2


【解决方案1】:

检查此MSDN article 声明:

隔离级别具有连接范围的范围,并且一旦设置为 与 SET TRANSACTION ISOLATION LEVEL 语句连接,它 在连接关闭或其他隔离之前一直有效 级别已设置。当连接关闭并返回池时, 上一个 SET TRANSACTION ISOLATION LEVEL 的隔离级别 声明被保留。重用池的后续连接 连接使用当时有效的隔离级别 连接是池化的。

问题是使用 Serializable 隔离级别打开连接;关联的事务被处理,连接也是如此,但连接没有被破坏并进入连接池。下一次(使用相同的连接字符串)发出连接请求时,该连接将被返回,并且由于查询未指定任何隔离级别,因此它在 Serializable 隔离级别中执行。

基本上,如果您有一个连接池并以特定的隔离级别(例如 Serializable)打开一个连接,那么该连接将返回到隔离级别设置为 Serializable 的池。下次您请求连接时,您无法确定不会返回此连接,因此即使默认隔离级别为 ReadCommitted,您也可能会获得这些“可序列化”连接之一。

另一个需要注意的是,每次将隔离级别设置为可序列化(或其他任何相关内容)时,您可能会选择不同的连接,并且通过将隔离级别设置为可序列化,您可能会慢慢污染连接池中越来越多的连接(或任何你设置的)。

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多