我正在尝试找到一种解决方案来解决 SQL Server 中反复出现的死锁情况。我对探查器跟踪生成的死锁图做了一些分析,并得出了以下信息:
第一个进程(spid 58)正在运行此查询:
UPDATE cds.dbo.task_core
SET nstate = 1
WHERE nmboxid = 89 AND ndrawerid = 1
AND nobjectid IN (SELECT
nobjectid
FROM (SELECT
nobjectid, count(nobjectid) AS counting
FROM cds.dbo.task_core
GROUP BY nobjectid
) task_groups
WHERE task_groups.counting > 1
)
第二个进程(spid 86)正在运行此查询:
INSERT INTO task_core (…) VALUES (…)
spid 58 正在等待 CDS.dbo.task_core 上的共享页面锁定 (spid 86 持有冲突的意图独占 (IX) 锁)
spid 86 正在等待 CDS.dbo.task_core 上的意图独占 (IX) 页锁定 (spid 58 持有冲突的更新锁)
最佳答案
很高兴您发布了声明和资源。为了充分理解这个问题,这些计划也很有用。但我将进行(有根据的)猜测并诊断死锁原因,因为更新的子查询中发生了大型扫描:
SELECT nobjectid
FROM (SELECT nobjectid, count(nobjectid) AS counting
FROM cds.dbo.task_core
GROUP BY nobjectid
) task_groups
WHERE task_groups.counting > 1
此查询必须扫描整个task_core 表。总是。您会在页面上遇到死锁,因为全表扫描已优化为使用页面锁定,但如果添加 ROWLOCK 提示,您也可以在行级别遇到死锁。
要消除死锁,必须消除更新过程中发生的全表扫描冲突。您可以尝试使用行级版本控制,在数据库中启用读已提交快照隔离,而不是使用脏读,请参阅 Understanding Row Versioning-Based Isolation Levels .
但是更好的解决方案是首先不进行扫描。首先,重新审视业务逻辑需求和数据模型。每当您看到需要查看整个表才能做出决定的更新时,这是一段非常非常难闻的代码。如果您确实发现更新无法以更明智的方式重写(我怀疑),那么您应该考虑使用索引 View 。 BIG_COUNT(*) 表达式在索引 View 中是允许的,它们会 speed up the query significantly ,除了消除死锁原因之外。
关于sql-server - 解决 SQL Server 死锁情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2449293/