2013-09-05 68 views
4

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

Update Deadlock Graph

Full Image

查询两个进程之间的几乎是相同的,该图显示了它作为:

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

任何人都可以揭示这可能是导致此任何光线?

回答

2

这是因为当您设置LatestLocalThreadID(以确保语句完成时行仍然存在)时,生成S锁的ForumThreads外键。一个可能的修复方法是在更新语句前添加

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

以便X锁定。您也可以尝试UPDLOCK作为较不积极的模式。这当然会在其他地方造成死锁,但这是最好的第一次尝试。

1

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

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

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