使用级联约束的可重现死锁

Posted

技术标签:

【中文标题】使用级联约束的可重现死锁【英文标题】:Reproducible Deadlock Using Cascading Constraints 【发布时间】:2009-12-14 20:33:26 【问题描述】:

我正在寻找代码来生成因使用级联约束而发生的可重现死锁。我可以在网上找到具体问题的参考资料,并且我已经回答了几十个关于使用级联约束的死锁的问题,但没有一个具有可重现的死锁版本。

我不是在寻找有关如何解决死锁、捕获或读取死锁图,或者我应该使用跟踪标志来获取死锁图的信息。我明白了,我想看看导致这种特定类型死锁的锁定细节。如果您可以提供允许我编写此死锁的复制品的细节,那就是一个足够好的答案。

我有许多脚本来重现其他类型的死锁,包括书签查找、使用显式事务的存储过程中的不一致表访问以及可序列化隔离下的存在性检查。我只是想不出级联约束死锁的重现。

【问题讨论】:

使用级联约束的两次删除之间的死锁,删除和任何其他操作之间的死锁,或单语句死锁(即 sql 错误)? 我将把它放在评论中,因为我没有尝试过并且不确定它是否会造成死锁,但尝试表 a 对表 b 和表具有 FK 的情况c 和表 b 也具有表 c 的 FK。我认为这可能会导致僵局。我很想看看你已经拥有的脚本来引发死锁。 Remus,你提到的第一个就是我想要引起的。 HLGEM,您不能像那样在 2005/2008 年创建循环依赖项。这是我尝试的第一件事。 【参考方案1】:

我意识到这篇文章已经很老了,但我有这样的情况。请在下面找到死锁信息和相关表格的链接:http://pastebin.com/cxqtGMgh 和 http://pastebin.com/5E8kw6Kw

您需要取消对我未包含的所有表的外键引用,并可能创建一些测试数据。根据下面的代码,页面引用PAGE: 16:8:5031979 被解析为profmaster 表。请注意,我使用了Metadata ObjectId 而不是输出中的m_objId,因为后者无法解析。

DBCC TRACEON(3604)
DBCC PAGE(16,8,5031979,1)
DBCC TRACEOFF(3604)

select name from sys.tables where object_id = 1889441805

这是页面解析报告的输出:http://pastebin.com/HfrVp2nP - 请注意我正在运行 SQL Server 2008 R2 (SP1) X64

对于如何解决问题的任何指导,我将不胜感激。

--e

<deadlock-list>
 <deadlock victim="process53f9f2bc8">
  <process-list>
   <process id="process53f9f2bc8" taskpriority="0" logused="4712" waitresource="KEY: 16:72057678434598912 (a60c363e20e5)" waittime="571706" ownerId="93354998" transactionname="user_transaction" lasttranstarted="2013-11-19T15:39:31.203" XDES="0x80011730" lockMode="U" schedulerid="2" kpid="2064" status="suspended" spid="61" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2013-11-19T15:39:31.263" lastbatchcompleted="2013-11-19T15:39:31.260" clientapp="3E WebUI" hostname="LA-BAT-26-WAPI" hostpid="2728" loginname="sa" isolationlevel="read committed (2)" xactid="93354998" currentdb="16" lockTimeout="4294967295" clientoption1="671096864" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="140" sqlhandle="0x02000000d1e0f407f28e46e45feec1ce34fc8f3e09dcb3c5">
update n0t0 set ProfMaster = @0 , MatrixTaxCode = null , PrevProfMaster = @1 , LastProcItemID = @2 , TimeStamp = GETDATE ( ) from Timecard as n0t0 where ( ( ( ( n0t0 . WorkDate ) &lt; = ( @3 ) ) and ( ( ( n0t0 . IsActive ) = ( @4 ) ) and ( ( n0t0 . IsNB ) = ( @5 ) ) ) ) and ( ( ( ( ( n0t0 . ProfMaster ) is null ) and ( ( n0t0 . InvMaster ) is null ) ) and ( ( n0t0 . WIPRemoveDate ) is null ) ) and ( ( n0t0 . CurrProcItemID ) is null ) ) ) and ( ( n0t0 . Matter ) in ( select n1t1 . Matter from ProfMatter as n1t1 where ( n1t1 . ProfMaster ) = ( @6 ) ) )     </frame>
     <frame procname="adhoc" line="1" sqlhandle="0x0200000095131921232b4d814cc188595c176663442618b6">
UPDATE n0t0 SET ProfMaster = 252516,MatrixTaxCode = NULL,PrevProfMaster = 252516,LastProcItemID = &apos;939f3291-10a7-4704-885e-9021b2a39f15&apos;,TimeStamp = GETDATE() FROM Timecard AS n0t0 WHERE ( ( ( ( n0t0.WorkDate ) &lt;= ( &apos;11/04/2013 00:00:00&apos;) ) AND ( ( ( n0t0.IsActive ) = ( 1 ) ) AND ( ( n0t0.IsNB ) = ( 0 ) ) ) ) AND ( ( ( ( ( n0t0.ProfMaster ) IS NULL ) AND ( ( n0t0.InvMaster ) IS NULL ) ) AND ( ( n0t0.WIPRemoveDate ) IS NULL ) ) AND ( ( n0t0.CurrProcItemID ) IS NULL ) ) ) AND ( ( n0t0.Matter ) IN ( SELECT n1t1.Matter FROM ProfMatter AS n1t1 WHERE ( n1t1.ProfMaster ) = ( 252516 ) ) )/**0x2C621659**/     </frame>
    </executionStack>
    <inputbuf>
UPDATE n0t0 SET ProfMaster = 252516,MatrixTaxCode = NULL,PrevProfMaster = 252516,LastProcItemID = &apos;939f3291-10a7-4704-885e-9021b2a39f15&apos;,TimeStamp = GETDATE() FROM Timecard AS n0t0 WHERE ( ( ( ( n0t0.WorkDate ) &lt;= ( &apos;11/04/2013 00:00:00&apos;) ) AND ( ( ( n0t0.IsActive ) = ( 1 ) ) AND ( ( n0t0.IsNB ) = ( 0 ) ) ) ) AND ( ( ( ( ( n0t0.ProfMaster ) IS NULL ) AND ( ( n0t0.InvMaster ) IS NULL ) ) AND ( ( n0t0.WIPRemoveDate ) IS NULL ) ) AND ( ( n0t0.CurrProcItemID ) IS NULL ) ) ) AND ( ( n0t0.Matter ) IN ( SELECT n1t1.Matter FROM ProfMatter AS n1t1 WHERE ( n1t1.ProfMaster ) = ( 252516 ) ) )/**0x2C621659**/    </inputbuf>
   </process>
   <process id="process50b54c8" taskpriority="0" logused="43622588" waitresource="PAGE: 16:8:5031979" waittime="1575" ownerId="87921480" transactionname="user_transaction" lasttranstarted="2013-11-19T14:26:29.400" XDES="0x569d39950" lockMode="U" schedulerid="9" kpid="1304" status="suspended" spid="60" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2013-11-19T15:49:01.277" lastbatchcompleted="2013-11-19T15:49:01.277" clientapp="3E WebUI" hostname="LA-BAT-27-WAPI" hostpid="2628" loginname="sa" isolationlevel="read committed (2)" xactid="87921480" currentdb="16" lockTimeout="4294967295" clientoption1="671096864" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="86" sqlhandle="0x020000006014e71626ea61a3e74df841cee6a59043438dc8">
update n0t0 set ProfStatus = @0 , LastProcItemID = @1 , TimeStamp = GETDATE ( ) from ProfMaster as n0t0 join #TempMatterProforma as z0 on ( ( n0t0 . ProfIndex ) = ( z0 . ProfIndex ) ) and ( ( z0 . IsNewProforma ) = ( @2 ) )     </frame>
     <frame procname="adhoc" line="1" sqlhandle="0x020000004d41a316b62a8171bbf8979051631fdc480c754b">
UPDATE n0t0 SET ProfStatus = N&apos;P&apos; ,LastProcItemID = &apos;d7eff077-6f52-435f-906a-6fc8f2ee929a&apos;,TimeStamp = GETDATE() FROM ProfMaster AS n0t0 JOIN #TempMatterProforma AS z0 ON ( ( n0t0.ProfIndex ) = ( z0.ProfIndex ) ) AND ( ( z0.IsNewProforma ) = ( 0 ) )/**0xA8DF8735**/     </frame>
    </executionStack>
    <inputbuf>
UPDATE n0t0 SET ProfStatus = N&apos;P&apos; ,LastProcItemID = &apos;d7eff077-6f52-435f-906a-6fc8f2ee929a&apos;,TimeStamp = GETDATE() FROM ProfMaster AS n0t0 JOIN #TempMatterProforma AS z0 ON ( ( n0t0.ProfIndex ) = ( z0.ProfIndex ) ) AND ( ( z0.IsNewProforma ) = ( 0 ) )/**0xA8DF8735**/    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057678434598912" dbid="16" objectname="TE_3E_BAT27B.dbo.Timecard" indexname="IDX__TimeIndex__2F97CBE5" id="lock1ffcaf600" mode="X" associatedObjectId="72057678434598912">
    <owner-list>
     <owner id="process50b54c8" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process53f9f2bc8" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
   <pagelock fileid="8" pageid="5031979" dbid="16" objectname="TE_3E_BAT27B.dbo.ProfMaster" id="lock3bf068600" mode="IX" associatedObjectId="72057678315388928">
    <owner-list>
     <owner id="process53f9f2bc8" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process50b54c8" mode="U" requestType="wait"/>
    </waiter-list>
   </pagelock>
  </resource-list>
 </deadlock>
</deadlock-list>

【讨论】:

以上是关于使用级联约束的可重现死锁的主要内容,如果未能解决你的问题,请参考以下文章

MariaDB“更新级联”约束没有按预期工作?

传播级联删除引发外键约束失败

MySQL外键约束,级联删除

Postgres 测试容器 - 如果存在级联,为啥要在删除表之前删除约束?

Android中使用SQLite的外键约束?在删除级联

引入 FOREIGN KEY 约束可能会导致循环或多个级联路径 - 为啥?