当插入两个不同的表时,我怎么会遇到死锁?

时间:2016-07-21 13:56:28

标签: sql-server sql-server-2012 database-deadlocks

这是一个DynamicsAX应用程序,我现在经常看到以下死锁。如果我正确理解输出,INSERT进入表CUSTTRANS将被INSERT阻塞到表CUSTSETTLEMENT中。我检查了两个表,都没有触发器,所以我不清楚如何导致另一个死锁? CUSTTRANS表确实启用了更改跟踪,但没有启用CUSTSETEMENT。

<event name="xml_deadlock_report" package="sqlserver" timestamp="2016-07-19T23:43:24.567Z">
  <data name="xml_report">
    <value>
      <deadlock>
        <victim-list>
          <victimProcess id="processb7c273c38" />
        </victim-list>
        <process-list>
          <process id="processb7c273c38" taskpriority="0" logused="9000" waitresource="KEY: 5:72057881131876352 (9006753b740b)" waittime="37640" ownerId="221473485" transactionname="user_transaction" lasttranstarted="2016-07-19T16:42:46.317" XDES="0xb7caa3078" lockMode="RangeS-S" schedulerid="6" kpid="1940" status="suspended" spid="122" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2016-07-19T16:42:46.760" lastbatchcompleted="2016-07-19T16:42:46.737" lastattention="2016-07-19T13:12:49.450" clientapp="Microsoft Dynamics AX" hostname="DW22" hostpid="3076" loginname="xxx" isolationlevel="read committed (2)" xactid="221473485" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
              <frame procname="adhoc" line="1" stmtstart="2872" sqlhandle="0x020000005b952a20985c14b98773bd4fb5fd593a90918fd00000000000000000000000000000000000000000">
INSERT INTO CUSTTRANS (ACCOUNTNUM,TRANSDATE,VOUCHER,...,REPORTINGEXCHADJUSTMENTRE    </frame>
              <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>(@P1 nvarchar(21),@P2 datetime2...@P67 numeric(32,4)</inputbuf>
          </process>
          <process id="process1d15b0cf8" taskpriority="0" logused="3009456" waitresource="KEY: 5:72057881131876352 (e7873f5a29fe)" waittime="3566" ownerId="221391316" transactionname="user_transaction" lasttranstarted="2016-07-19T16:38:55.940" XDES="0x21b5e31d8" lockMode="RangeI-N" schedulerid="3" kpid="6320" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2016-07-19T16:43:20.997" lastbatchcompleted="2016-07-19T16:43:20.993" lastattention="2016-07-19T15:31:56.060" clientapp="Microsoft Dynamics AX" hostname="DW22" hostpid="3076" loginname="xxxxx" isolationlevel="read committed (2)" xactid="221391316" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
              <frame procname="adhoc" line="1" stmtstart="1262" sqlhandle="0x020000000af3f41be10a624051e59a5f47e43bd38431bc5f0000000000000000000000000000000000000000">
INSERT INTO CUSTSETTLEMENT (TRANSRECID,TRANSDATE,OFFSETTRANSVOUCHER,...,RECID) VALUES (@P1,@P2,@P3...,@P40)    </frame>
            </executionStack>
            <inputbuf>
(@P1 bigint,@P2 datetime2,@P3 nvarchar(21)...,@P40 bigint)INSERT INTO CUSTSETTLEMENT (TRANSRECID,TRANSDATE,OFFSETTRANSVOUCHER,...</inputbuf>
          </process>
        </process-list>
        <resource-list>
          <keylock hobtid="72057881131876352" dbid="5" objectname="MicrosoftDynamicsAX.dbo.CUSTSETTLEMENT" indexname="I_075TRANSINDEX" id="lock6d97d4380" mode="RangeX-X" associatedObjectId="72057881131876352">
            <owner-list>
              <owner id="process1d15b0cf8" mode="RangeX-X" />
            </owner-list>
            <waiter-list>
              <waiter id="processb7c273c38" mode="RangeS-S" requestType="wait" />
            </waiter-list>
          </keylock>
          <keylock hobtid="72057881131876352" dbid="5" objectname="MicrosoftDynamicsAX.dbo.CUSTSETTLEMENT" indexname="I_075TRANSINDEX" id="lock7102fa100" mode="RangeS-S" associatedObjectId="72057881131876352">
            <owner-list>
              <owner id="processb7c273c38" mode="RangeS-S" />
            </owner-list>
            <waiter-list>
              <waiter id="process1d15b0cf8" mode="RangeI-N" requestType="wait" />
            </waiter-list>
          </keylock>
        </resource-list>
      </deadlock>
    </value>
  </data>
  <action name="collect_system_time" package="package0">
    <value>2016-07-19T23:43:24.567Z</value>
  </action>
  <action name="client_hostname" package="sqlserver">
    <value />
  </action>
  <action name="context_info" package="sqlserver">
    <value />
  </action>
  <action name="attach_activity_id_xfer" package="package0">
    <value>CE2E9A01-A31C-464F-9288-AC45C7927760-574</value>
  </action>
  <action name="attach_activity_id" package="package0">
    <value>634B86DC-58AB-4870-9170-5575B9C12D0A-1</value>
  </action>
</event>

1 个答案:

答案 0 :(得分:0)

首先想到的是(不看图) - 它们之间有一个FK。而且我认为它确实在那里。

CUSTTRANS可能是子表,CUSTSETTLEMENT是父表。插入CUSTTRANS时 - 服务器检查父表CUSTSETTLEMENT中是否有适当的密钥(从CUSTTRANS行引用)。并对该列上的父表/索引中的键放置共享锁。

第二个事务是在父表CUSTSETTLEMENT中插入值并更新I_075TRANSINDEX索引。我假设您在一个事务中在该表中插入了许多值,因此在某些时刻您已经使用独占锁锁定了一些范围并尝试锁定更多。但是 - 在另一个范围 - 已经从第一个插入到CUSTTRANS的共享锁定,它检查父表中是否存在相应的行以确保FK完整性。

是的,FK有一些非常常见的与它们相关的死锁场景。另一个是:将多个(足以启用升级)插入子表并从父表中删除许多 - 两者都将尝试锁定整个相关表并将失败。

解决方案(一如既往):

  • 提高隔离级别,按顺序执行这些查询
  • 禁用服务器的完整性控制机制,并在需要时自行完成(丢弃或禁用FK - 是的,这是在困难情况下的常见解决方案)
  • 缩短您的交易和锁定范围 - 一次性进行较少的行数
  • 使用try-catch and retry
  • 处理死锁