2

我在 SQL Server 2008 R2 上遇到了死锁问题。在 SQL Profiler 中查看死锁图时,问题似乎源于查询通知:

  <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 监视的表时似乎发生了死锁。

我不太了解死锁图语法。KeyLock 模式仅在使用可序列化事务隔离级别时为 RangeS-U。, 对 ?

我也读过这个问题......我应该激活 READ_COMMITED_SNAPSHOT 吗?

谢谢...

4

2 回答 2

2

不能确定,但​​这里有一些想法......

导致通知的语句可能在通知传递之前未完成。因此,当从服务代理接收到通知并对通知采取任何操作时,它可能仍然具有活动锁。

也许您的通知收件人正在尝试清理队列或在生成第一个通知的事务完成之前从队列中获取第二个通知。

生成通知的 DML 是否在多步骤事务中运行?是在多步骤事务中运行的接收通知的代码。(即您是否使用了 begin tran 或等价物?)。

跟踪死锁图中提到的进程并了解哪些代码持有 RangeX-X 锁以及哪些代码持有 RangeS-U 可能很有用。

您可能希望发布一些生成通知的代码和接收通知的代码的最小示例。

这里还有一个关于通知和多个订阅的已知有点类似死锁问题的 Microsoft KB。

MS KB975090 可能相关,但不完全相同。

于 2012-06-08T17:39:46.083 回答
0

其背后的主要原因是事务太长并且涉及的对象太多。

正如我在问题中所说,触发 SqlDependency 的表包含对数据库中每个对象的引用。在同一个事务中更新一堆对象意味着查询通知系统会锁定这个大表。因此,您很快就会陷入僵局。

2 个解决方案(由 MS 建议):

  • 减少交易的长度和复杂性。
  • 在大交易之外执行触发通知系统的请求。
于 2012-10-25T09:36:46.253 回答