我有一个网站上有一个非常受欢迎的论坛,偶尔我会在同一个论坛上看到两个相同(减去其中的数据)更新语句之间发生的几个死锁。我不确定为什么会在这个查询上发生这种情况,因为网站上有许多其他查询以高并发性运行而没有问题。
两个进程之间的查询几乎相同,图表显示为:
update [Forum] set [DateModified] = @DateModified, [LatestLocalThreadID] = @LatestLocalThreadID where ID = 310
任何人都可以解释可能造成这种情况的原因吗?
答案 0 :(得分:3)
这是因为ForumThreads
有一个外键,当你设置LatestLocalThreadID
时会生成一个S锁(以确保在语句完成时该行仍然存在)。可能的解决方法是使用
SELECT *
FROM ForumThreads WITH (XLOCK, ROWLOCK, HOLDLOCK)
WHERE ID = @LatestLocalThreadID
为了X锁定。您也可以尝试UPDLOCK
作为不太激进的模式。这当然可以在其他地方造成死锁,但这是最好的第一次尝试。
答案 1 :(得分:1)
通常以相同的顺序访问对象(表,页,行)来防止死锁。在您的示例中,有一个进程首先访问forum
,第二个访问forumThread
,另一个进程反之亦然。 update
通常首先搜索要更新的行,并在搜索期间使用S锁。它已识别出要更改的行被X锁锁定,然后发生实际更改。
快速而肮脏的解决方案可能是按照您需要的顺序执行begin Tran
然后lock
对象,然后执行更新,然后再次释放锁定的commit
。但是这会因为阻止锁定而降低网站的整体吞吐量。
更好的方法是识别这两个陈述(您可能会编辑您的问题,并在找到它时给我们另一个陈述)及其执行计划。应该可以以某种方式重写事务以相同的顺序访问所有对象 - 并防止死锁。