即使表之间没有关系也会遇到死锁

3 sql-server deadlock locking

我一直在研究死锁,它是不同的原因。我找到了一个关于这个问题的例子,但我无法完全理解死锁的原因,因为涉及两个不同的表,到目前为止我读到的是只涉及一个表!

首先,我在连接 1 中运行此查询:

Begin Tran

 Update  Purchasing.PurchaseOrderHeader
 Set Freight = Freight * 0.9
 Where PurchaseOrderID = 1255;
Run Code Online (Sandbox Code Playgroud)

我再次在连接 2 中运行此查询:

update Purchasing.PurchaseOrderDetail
Set OrderQty = 4
Where ProductID = 448 and
      PurchaseOrderID = 1255
Run Code Online (Sandbox Code Playgroud)

回到连接 1 我运行这个查询(这会导致死锁):

Begin Transaction

             Update Purchasing.PurchaseOrderDetail
             Set OrderQty = 2
             where ProductID = 448 and
                   PurchaseOrderID = 1255
Run Code Online (Sandbox Code Playgroud)

可以看到,事务中涉及到两张表,那么到底是什么导致了死锁呢??提前致谢

Dan*_*man 5

我无法完全理解死锁的原因,因为涉及两个不同的表,而我目前所读的是只涉及一个表!

当 2 个或更多会话相互等待时会发生死锁。死锁资源是同一个表、不同表、整个对象等中的行都没有关系。

我运行了您的脚本来重现死锁,xml_deadlock_reportsystem_healthXE 跟踪中提取列,并将死锁报告 XML 保存到带有.xdl扩展名的文件中。下面是来自 SSMS 的图形视图。

xml_deadlock_report

如您所见,SPID 58 受害者正在等待Purchasing.PurchaseOrderDetail更新键锁,但被同一键上的 SPID 53 独占键锁阻止。SPID 53 正在等待更新Purchasing.PurchaseOrderHeader密钥锁,被保存在同一密钥上的排他锁 SPID 58 阻止。

下面是原始的 xml_deadlock_report XML。

<deadlock>
  <victim-list>
    <victimProcess id="process1a668c9eca8"/>
  </victim-list>
  <process-list>
    <process id="process1a668c9eca8" taskpriority="0" logused="400" waitresource="KEY: 6:72057594048348160 (4ab5f0d47ad5)" waittime="1316" ownerId="2500187" transactionname="user_transaction" lasttranstarted="2018-07-24T06:02:13.303" XDES="0x1a85b00c490" lockMode="U" schedulerid="3" kpid="2932" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-07-24T06:02:31.437" lastbatchcompleted="2018-07-24T06:02:31.433" lastattention="2018-07-24T06:00:22.400" clientapp="Microsoft SQL Server Management Studio - Query" hostname="SQLSERVER" hostpid="15904" loginname="DOMAINNAME\USERNAME" isolationlevel="read committed (2)" xactid="2500187" currentdb="6" lockTimeout="4294967295" clientoption1="671090784" clientoption2="390200">
      <executionStack>
        <frame procname="adhoc" line="1" stmtstart="64" stmtend="278" sqlhandle="0x02000000d0c7f31a30fb1ad425c34357fe8ef6326793e7aa0000000000000000000000000000000000000000">  unknown    </frame>
        <frame procname="adhoc" line="1" stmtstart="26" stmtend="326" sqlhandle="0x02000000b66e4532b6686980baf466a9597258f2464dd4f50000000000000000000000000000000000000000">  unknown    </frame>
      </executionStack>
      <inputbuf>               Update Purchasing.PurchaseOrderDetail               Set OrderQty = 2               where ProductID = 448 and                     PurchaseOrderID = 1255   </inputbuf>
    </process>
    <process id="process1a66883d848" taskpriority="0" logused="9484" waitresource="KEY: 6:72057594048413696 (4bc08edebc6b)" waittime="16176" ownerId="2500193" transactionname="user_transaction" lasttranstarted="2018-07-24T06:02:16.577" XDES="0x1a85e004490" lockMode="U" schedulerid="5" kpid="20416" status="suspended" spid="53" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-07-24T06:02:16.577" lastbatchcompleted="2018-07-24T06:02:16.570" lastattention="2018-07-24T06:01:28.820" clientapp="Microsoft SQL Server Management Studio - Query" hostname="SQLSERVER" hostpid="15904" loginname="DOMAINNAME\USERNAME" isolationlevel="read committed (2)" xactid="2500193" currentdb="6" lockTimeout="4294967295" clientoption1="673319008" clientoption2="390200">
      <executionStack>
        <frame procname="AdventureWorks2014.Purchasing.uPurchaseOrderDetail" line="39" stmtstart="2732" stmtend="3830" sqlhandle="0x0300060004cc856a0ee00a016ba3000000000000000000000000000000000000000000000000000000000000">  UPDATE [Purchasing].[PurchaseOrderHeader]              SET [Purchasing].[PurchaseOrderHeader].[SubTotal] =                   (SELECT SUM([Purchasing].[PurchaseOrderDetail].[LineTotal])                      FROM [Purchasing].[PurchaseOrderDetail]                      WHERE [Purchasing].[PurchaseOrderHeader].[PurchaseOrderID]                           = [Purchasing].[PurchaseOrderDetail].[PurchaseOrderID])              WHERE [Purchasing].[PurchaseOrderHeader].[PurchaseOrderID]                   IN (SELECT inserted.[PurchaseOrderID] FROM inserted    </frame>
        <frame procname="adhoc" line="3" stmtstart="64" stmtend="278" sqlhandle="0x02000000d0c7f31a30fb1ad425c34357fe8ef6326793e7aa0000000000000000000000000000000000000000">  unknown    </frame>
        <frame procname="adhoc" line="3" stmtstart="28" stmtend="250" sqlhandle="0x02000000cac3a70ebbbc20e8360adb397f4986f2ced020140000000000000000000000000000000000000000">  unknown    </frame>
      </executionStack>
      <inputbuf>  Begin Tran    update Purchasing.PurchaseOrderDetail  Set OrderQty = 4  Where ProductID = 448 and        PurchaseOrderID = 1255   </inputbuf>
    </process>
  </process-list>
  <resource-list>
    <keylock hobtid="72057594048348160" dbid="6" objectname="AdventureWorks2014.Purchasing.PurchaseOrderDetail" indexname="PK_PurchaseOrderDetail_PurchaseOrderID_PurchaseOrderDetailID" id="lock1a7fea46a00" mode="X" associatedObjectId="72057594048348160">
      <owner-list>
        <owner id="process1a66883d848" mode="X"/>
      </owner-list>
      <waiter-list>
        <waiter id="process1a668c9eca8" mode="U" requestType="wait"/>
      </waiter-list>
    </keylock>
    <keylock hobtid="72057594048413696" dbid="6" objectname="AdventureWorks2014.Purchasing.PurchaseOrderHeader" indexname="PK_PurchaseOrderHeader_PurchaseOrderID" id="lock1a815dda900" mode="X" associatedObjectId="72057594048413696">
      <owner-list>
        <owner id="process1a668c9eca8" mode="X"/>
      </owner-list>
      <waiter-list>
        <waiter id="process1a66883d848" mode="U" requestType="wait"/>
      </waiter-list>
    </keylock>
  </resource-list>
</deadlock>
Run Code Online (Sandbox Code Playgroud)

示例AdventureWorks数据库包括导致此死锁的表UPDATE触发器Purchasing.PurchaseOrderDetail。触发插入到Production.TransactionHistory也同时更新Purchasing.PurchaseOrderHeaderPurchasing.PurchaseOrderDetailProductIDOrderQtyUnitPrice列被更新。

总之,导致这个僵局的顺序是:

1) 连接 1 更新了一个Purchasing.PurchaseOrderHeader但没有提交

2) 连接 2 更新了Purchasing.PurchaseDetail表,尝试更新时触发的触发器被阻止Purchasing.PurchaseOrderHeader

3) connection 1 tried to update Purchasing.PurchaseDetail but was blocked by connection

4) SQL Server chose connection 1 as the deadlock victim, allowing connection 2 to autocommit