5

我有一个网站,上面有一个非常受欢迎的论坛,我偶尔会看到在同一论坛上的两个相同(减去其中的数据)更新语句之间发生了几个死锁。我不确定为什么会在此查询上发生这种情况,因为该站点上还有许多其他查询以高并发运行而没有问题。

更新死锁图

全图

两个进程之间的查询几乎相同,图表显示为:

update [Forum] set [DateModified] = @DateModified, [LatestLocalThreadID] = @LatestLocalThreadID where ID = 310     

任何人都可以阐明可能导致这种情况的原因吗?

4

2 回答 2

3

这是因为有一个外键会ForumThreads在您设置时生成 S 锁LatestLocalThreadID(以确保在语句完成时该行仍然存在)。一个可能的解决方法是在更新语句前面加上

SELECT *
FROM ForumThreads WITH (XLOCK, ROWLOCK, HOLDLOCK)
WHERE ID = @LatestLocalThreadID 

为了对此进行 X 锁定。您也可以尝试UPDLOCK使用不那么激进的模式。这当然会在其他地方造成死锁,但这是最好的第一次尝试。

于 2013-09-05T15:37:10.910 回答
1

基本上,通过始终以相同的顺序访问对象(表、页、行)来防止死锁。在您的示例中,有一个进程访问forum第一个和forumThread第二个,另一个线程反之亦然。Anupdate通常首先搜索要更新的行,并在搜索期间使用 S 锁。它已确定要更改的行被 X 锁锁定,然后发生实际更改。

快速而肮脏的解决方案可能是按照您需要的顺序执行对象,begin Tran然后lock执行更新,然后commit再次释放锁。但这会因为阻塞锁而降低您网站的整体吞吐量。

更好的方法是确定这两个语句(您可以编辑您的问题并在找到时给我们另一个)和它们的执行计划。应该可以以某种方式重写事务以以相同的顺序访问所有对象 - 并防止死锁。

于 2013-09-05T15:56:23.820 回答