我在SQL Server 2008 R2上遇到了死锁问题。查看SQL事件探查器中的死锁图时,问题似乎源于查询通知:
<resource-list>
<keylock hobtid="72057654759522304" dbid="6" objectname="MyDB.sys.query_notification_814081939" indexname="cidx" id="lock15ab2aa80" mode="RangeX-X" associatedObjectId="72057654759522304">
<owner-list>
<owner id="process5c5708" mode="RangeX-X"/>
</owner-list>
<waiter-list>
<waiter id="process4e9ae08" mode="RangeS-U" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057654759522304" dbid="6" objectname="MyDB.sys.query_notification_814081939" indexname="cidx" id="lock15e56a300" mode="RangeS-U" associatedObjectId="72057654759522304">
<owner-list>
<owner id="process4e9ae08" mode="RangeS-U"/>
</owner-list>
<waiter-list>
<waiter id="process5c5708" mode="RangeS-U" requestType="wait"/>
</waiter-list>
</keylock>
</resource-list>
这些查询通知是使用SQLDependency实现的。 更新由SQLDependency监视的表时,似乎发生了死锁。
我真的不了解死锁图语法。关键锁模式是RangeS-U only while using the serializable transaction isolation level.,对吗?
我也读过这个question ...我应该激活READ_COMMITED_SNAPSHOT吗?
... THX
答案 0 :(得分:2)
无法确定下来,但这里有一些想法...
导致通知的声明可能无法在通知发送之前完成。因此,当从服务代理收到通知并且对通知采取任何操作时,它可能仍然具有活动锁。
在生成第一个通知的事务完成之前,通知您的通知收件人可能正在尝试清理队列或从队列中获取第二个通知。
生成通知的DML是否在多步骤事务中运行?接收通知的代码是否在多步事务中运行。 (即你是否使用begin tran或同等学历?)。
跟踪死锁图中提到的进程并了解哪些代码包含RangeX-X锁以及哪个代码保存RangeS-U可能很有用。
您可能希望发布一些生成通知的代码和接收通知的代码的最小示例。
此处还有一个Microsoft KB,它讲述了一个类似于通知和多个订阅的类似死锁问题。
答案 1 :(得分:0)
背后的主要原因是事务太长并且涉及太多对象。 正如我在我的问题中所说,触发sqldependency的表包含对数据库中每个对象的引用。更新同一事务中的一堆对象意味着查询通知系统会锁定此大表。因此,你很快陷入僵局。
2个解决方案(MS建议): - 减少交易的长度和复杂性。 - 在大事务之外执行触发通知系统的请求。
希望它有所帮助...