SQL Server书签查找死锁解决方案



我在应用程序中检测到书签查找死锁,无法决定使用哪种解决方案。它们似乎都不是最优的。

以下是查询:

UPDATE TEST SET DATA = @data WHERE CATEGORY = @cat
SELECT DATA, EXTRA_COLUMN FROM TEST WHERE CATEGORY = @cat

问题是CATEGORY和DATA中有一个未聚集的索引,这两个查询使用该索引的顺序与聚集索引的顺序相反。

即:update锁定聚集索引并更新表,select锁定未聚集索引以进行书签查找,两者都希望对方锁定(死锁)。

以下是我发现的选项:

1-创建一个索引,该索引包括select查询中的所有列。-它起了作用,但我认为这不是一个好主意,我必须包括任何选择查询中使用的任何列,这些列可以在应用程序中的任何地方更新。

2-将数据库的事务隔离级别更改为COMMITTED_NAPSHOT

3-向选择添加NOLOCK提示

4-删除索引

5-在其中一个事务有机会获得最终阻止另一个事务的锁之前,强制它在较早的时候阻止该事务。(不起作用)

我认为第二个选项是最好的选择,但我知道它可能会产生其他问题,COMMITTED_NAPSHOT不应该是SQL SERVER中的默认隔离级别吗?

在我看来,无论是在应用程序中还是在数据库逻辑中都没有任何错误,这是一个带有未聚集索引的简单表和两个访问同一表的查询,一个要更新,另一个要选择。

解决这个问题的最佳方法是什么?还有其他解决方案吗?

我真的希望SQL Server能够自己解决这个问题。

快照隔离是一个非常强大的解决方案,可以从等式中删除读取。许多关系数据库管理系统一直都有它们。它们在实践中不会引起很多问题。与一些手动的脆性解决方案(如非常特定的索引或提示)相比,更喜欢此解决方案。

请尝试在Category(包括Data&Extra_Column)上添加非聚集索引,并向您的查询添加以下提示:

UPDATE t SET t.DATA = @data FROM TEST WITH (index(ix_Cat)) WHERE CATEGORY = @cat
SELECT DATA, EXTRA_COLUMN FROM TEST WITH (index(ix_Cat)) WHERE CATEGORY = @cat

这将确保两个查询以相同的顺序更新/选择数据,并防止它们彼此死锁。

最新更新