SQLServer死锁
我有一个Java应用程序正在数据库上执行多个并发CRUD操作。 我添加了对SQLServer的支持,但是在并发删除期间遇到了死锁问题。 经过一番调查后发现问题可能是由于特定表上的锁升级造成的。
为了解决这个问题,我决定使用UPDLOCK提示来完成所有关于表格的读取操作,以便避免死锁。 但是,我仍然看到这个问题。 我在SQLServer中启用了跟踪,并在SQLServer日志中发现了以下死锁跟踪:
遇到死锁....打印死锁信息等待图
节点:1 KEY:5:72057594042384384(54048e7b3828)CleanCnt:3模式:X标志:为0x0授予列表1:拥有者:0x03D08C40模式:X FLG:为0x0价:0寿命:02000000 SPID:62 ECID:0 XACTLOCKINFO:0x04834274 SPID: 62 ECID:0语句类型:DELETE线#:1个输入BUF:语言事件:(@ P0为nvarchar(4000))从part_data删除其中PART_ID = @ P0请求者:ResType:LockOwner S类型:'OR'Xdes:0x04B511C8模式: U SPID:60 BatchID:0 ECID:0 TaskProxy:(0x058BE378)值:0x3d08500成本:(0/1296)
节点:2
KEY:5:72057594042384384(f903d6d6e0ac)CleanCnt:2模式:X标志:为0x0授予列表0:拥有者:0x03D088A0模式:X FLG:为0x0价:0寿命:02000000 SPID:60 ECID:0 XACTLOCKINFO:0x04B511EC SPID:60 ECID: 0语句类型:DELETE线#:1个输入BUF:语言事件:(@ P0为nvarchar(4000))从part_data删除其中PART_ID = @ P0请求者:ResType:LockOwner S类型:'OR'Xdes:0x04834250模式:U SPID: 62 BatchID:0 ECID:0 TaskProxy:(0x047BA378)值:0x3d089e0成本:(0/4588)
受害者资源所有者:ResType:LockOwner S类型:'OR'Xdes:0x04B511C8模式:U SPID:60 BatchID:0 ECID:0 TaskProxy:(0x058BE378)值:0x3d08500成本:(0/1296)
SQLServer分析器显示这是两个客户端持有更新(U)锁并尝试升级到独占(X)锁。 我读过的SQLServer文档说只有一个客户端可以在给定时间在表上有一个(U)锁,所以我想知道为什么我看到跟踪中显示的情况。
在该跟踪中引用的数据库对象是外键上的索引。 如果任何有解决这类问题经验的人可以提供建议,这将是一个很大的帮助。
谢谢,布拉德。
编辑添加死锁图xml请求:
<deadlock-list>
<deadlock victim="process989018">
<process-list>
<process id="process6aa7a8" taskpriority="0" logused="4844" waitresource="KEY: 5:72057594042384384 (5504bdfb7529)" waittime="9859" ownerId="613553" transactionname="implicit_transaction" lasttranstarted="2009-05-08T11:52:39.137" XDES="0x5fcbc30" lockMode="U" schedulerid="1" kpid="3516" status="suspended" spid="59" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2009-05-08T11:52:39.183" lastbatchcompleted="2009-05-08T11:52:39.183" clientapp="jTDS" hostname="LOIRE" hostpid="123" loginname="sa" isolationlevel="read committed (2)" xactid="613553" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="40" sqlhandle="0x0200000007c76c39efdd8317c6fa7b611b4fd958f05cfcf4">
delete from part_data where part_id = @P0 </frame>
</executionStack>
<inputbuf>(@P0 nvarchar(4000))delete from part_data where part_id = @P0</inputbuf>
</process>
<process id="process989018" taskpriority="0" logused="1528" waitresource="KEY: 5:72057594042384384 (5e0405cb0377)" waittime="1250" ownerId="613558" transactionname="implicit_transaction" lasttranstarted="2009-05-08T11:52:39.183" XDES="0x48318f0" lockMode="U" schedulerid="2" kpid="2692" status="suspended" spid="60" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2009-05-08T11:52:39.183" lastbatchcompleted="2009-05-08T11:52:39.183" clientapp="jTDS" hostname="LOIRE" hostpid="123" loginname="sa" isolationlevel="read committed (2)" xactid="613558" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="40" sqlhandle="0x0200000007c76c39efdd8317c6fa7b611b4fd958f05cfcf4">
delete from part_data where part_id = @P0 </frame>
</executionStack>
<inputbuf>(@P0 nvarchar(4000))delete from part_data where part_id = @P0</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594042384384" dbid="5" objectname="MESSAGESTOREDB61.dbo.part_data" indexname="idx_part_data_part_id" id="lock3cab740" mode="X" associatedObjectId="72057594042384384">
<owner-list>
<owner id="process6aa7a8" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process989018" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594042384384" dbid="5" objectname="MESSAGESTOREDB61.dbo.part_data" indexname="idx_part_data_part_id" id="lock3cad340" mode="X" associatedObjectId="72057594042384384">
<owner-list>
<owner id="process989018" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process6aa7a8" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>
欢迎来到可怕的。
上次遇到这种情况时,这是因为更新或删除无法找到一个好的索引来帮助它隔离它所影响的行。 这导致了一个不稳定的锁定升级,因为它使用非覆盖索引修改查找记录。
因此,如果你可以隔离一些查询,请检查它们的sql,看看你是否无法尝试提供一些覆盖索引。
覆盖索引是包含特定where子句中所有字段的索引。
SQLServer上的死锁几乎总是来源于单个线程尝试使用两个连接进行写入和读取并因此使用两个事务的事实。 如果你想完成这个工作,使用ONE连接在单个线程中执行所有操作,并确保你确实重新使用连接。 这可能是由于应用程序中的层次意外使用了不同的连接进行读取期间的读取,这使得读取等待其他代码(使用另一个连接)来完成,因为读取永远不会结束。
示例(伪步骤)
开始反式
首先不要使用提示,通常SQL Server最好自己留下。
Secondo验证你没有一个真正的死锁(但它发生的死锁外观可以提示的次数少得多)。
第三,正如有人建议的那样,检查你是否有一些缓慢的查询并调整它。
根据我的经验, 每次客户报告发生死锁情况时,都会发生这种情况,因为运行缓慢的查询升级并且从不发生真正的死锁,调整查询或添加特定索引始终解决了问题。
我没有看到你正在谈论的SQL Server版本,但是每个后续版本的死锁管理都比前一版本更好,而SQL Server 2000在这个主题中特别讨厌。
问候
马西莫
上一篇: SQLServer deadlock