两个更新语句之间的SQL Server死锁

时间:2013-09-05 15:33:03

标签: sql-server database-deadlocks

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

Update Deadlock Graph

Full Image

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

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

任何人都可以解释可能造成这种情况的原因吗?

2 个答案:

答案 0 :(得分:3)

这是因为ForumThreads有一个外键,当你设置LatestLocalThreadID时会生成一个S锁(以确保在语句完成时该行仍然存在)。可能的解决方法是使用

为update语句添加前缀
SELECT *
FROM ForumThreads WITH (XLOCK, ROWLOCK, HOLDLOCK)
WHERE ID = @LatestLocalThreadID 

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

答案 1 :(得分:1)

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

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

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