Jus*_*Deq 5 sql-server deadlock sql-server-2016
我正在使用 SQL Server 2016 并遇到一种情况,即通过页锁在两个不同的表上发生死锁。据我了解,数据库从不跨表共享页面,那么从表栏中选择怎么可能阻止表foo上的更新?特别是考虑到foo没有传入或传出的 FK(它是一个独立的、隔离的表)。
这是死锁xml:
<deadlock>
<victim-list>
<victimProcess id="process200e2c2cca8"/>
</victim-list>
<process-list>
<process id="process200e2c2cca8" taskpriority="0" logused="528" waitresource="PAGE: 7:1:463762 " waittime="2813" ownerId="232195085" transactionname="implicit_transaction" lasttranstarted="2019-06-18T01:57:05.067" XDES="0x201379a6430" lockMode="IX" schedulerid="2" kpid="2780" status="suspended" spid="77" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2019-06-18T01:57:05.267" lastbatchcompleted="2019-06-18T01:57:05.267" lastattention="1900-01-01T00:00:00.267" clientapp="Microsoft JDBC Driver for SQL Server" hostname="EC2AMAZ-U81HN6O" hostpid="0" loginname="mydb" isolationlevel="read committed (2)" xactid="232195085" currentdb="7" currentdbname="mydb" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="684" stmtend="1618" sqlhandle="0x0200000068ff5415175911deba600fac1e2197ddfe8b65890000000000000000000000000000000000000000"> unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"> unknown </frame>
</executionStack>
<inputbuf> update foo set version=@P0, field1=@P1, ... fieldN=@PN where id=@P25 and version=@P26 </inputbuf>
</process>
<process id="process2013de9b848" taskpriority="0" logused="1252" waitresource="PAGE: 7:1:481017 " waittime="2786" ownerId="232194529" transactionname="implicit_transaction" lasttranstarted="2019-06-18T01:57:03.300" XDES="0x2012a5ea430" lockMode="S" schedulerid="1" kpid="2884" status="suspended" spid="93" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2019-06-18T01:57:05.280" lastbatchcompleted="2019-06-18T01:57:05.280" lastattention="1900-01-01T00:00:00.280" clientapp="Microsoft JDBC Driver for SQL Server" hostname="EC2AMAZ-U81HN6O" hostpid="0" loginname="mydb" isolationlevel="read committed (2)" xactid="232194529" currentdb="7" currentdbname="mydb" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="132" stmtend="460" sqlhandle="0x02000000b1cb870e1f69a812df19c828461940c4f02bf9230000000000000000000000000000000000000000"> unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"> unknown </frame>
</executionStack>
<inputbuf> select count(*) as ct from bar where proj_id=@P0 and biz=@P1 and baz=@P2 and status<>@P3 and status<>@P4 </inputbuf>
</process>
</process-list>
<resource-list>
<pagelock fileid="1" pageid="463762" dbid="7" subresource="FULL" objectname="mydb.dbo.foo" id="lock2011f3b5b80" mode="SIX" associatedObjectId="72057594055753728">
<owner-list>
<owner id="process2013de9b848" mode="SIX"/>
</owner-list>
<waiter-list>
<waiter id="process200e2c2cca8" mode="IX" requestType="wait"/>
</waiter-list>
</pagelock>
<pagelock fileid="1" pageid="481017" dbid="7" subresource="FULL" objectname="mydb.dbo.bar" id="lock200bdfb6980" mode="IX" associatedObjectId="72057594042974208">
<owner-list>
<owner id="process200e2c2cca8" mode="IX"/>
</owner-list>
<waiter-list>
<waiter id="process2013de9b848" mode="S" requestType="convert"/>
</waiter-list>
</pagelock>
</resource-list>
</deadlock>
Run Code Online (Sandbox Code Playgroud)
具有不同页面的两个不同表如何创建页面锁死锁?
Jos*_*ell 10
这是一个典型的死锁,但很难在 SSMS 中或仅通过查看 XML 来判断。这两个表都在两个会话中被访问。
在SentryOne 计划资源管理器中查看它更容易一些,您还可以点击“播放”按钮来观看死锁的时间安排。这是一个屏幕截图:
这是发生的事情:
dbo.foo
<inputbuf>
元素中dbo.bar
<inputbuf>
元素中dbo.foo
在第 1 步中锁定
的页面上获取 IX 锁update foo...where id=@P25 and version=@P26
该语句被包含在<inputbuf>
元素dbo.bar
在第 2 步中锁定
的页面上获取 S 锁select count(*) as ct from bar where...
其被包括在所述<inputbuf>
元件因此陷入僵局。
您需要跟踪运行这些查询的代码,并查看每个批处理/事务中正在运行的其他语句。<inputbuf>
元素中显示的查询文本可能会产生误导,因为它可以被截断,并且它不一定显示在事务期间执行的每个语句(您可以在 Erik Darling 的博客上看到一个很好的例子)。
我注意到连接使用了“implicit_transaction”,这是 SQL Server JDBC 驱动程序的一个不幸的“特性”。setAutoCommit(true)
如果您不打算在事务中执行此连接的所有语句,您可能希望调用。这可能会解决您的死锁问题。
如果您确实需要在事务中完成所有这些工作,避免这种死锁的经典建议是确保以相同的顺序获取和释放锁。如果没有看到您的代码,很难比这更具体,但是如果您有任何问题,请告诉我。