【问题标题】:SQL Server Bookmark Lookup Deadlock solutionSQL Server 书签查找死锁解决方案
【发布时间】:2015-06-27 16:49:57
【问题描述】:

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

这里是查询:

 UPDATE TEST SET DATA = @data WHERE CATEGORY = @cat

 SELECT DATA, EXTRA_COLUMN FROM TEST WHERE CATEGORY = @cat

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

即:更新锁定聚集索引并更新表,而选择锁定非聚集索引以进行书签查找,并且它们都希望彼此锁定(死锁)。

以下是我找到的选项:

1 - 创建一个包含选择查询中所有列的索引。 - 它有效,但我认为这不是一个好主意,我必须包含在任何选择查询中使用的任何列,这些列可以在应用程序的任何位置更新。

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

3 - 向选择添加 NOLOCK 提示

4 - 删除索引

5 - 强制其中一个事务在有机会获得最终阻塞另一个事务的锁之前在较早的时间点阻塞。 (没用)

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

在我看来,应用程序或数据库逻辑中都没有任何错误,它是一个简单的表,具有非聚集索引和访问同一个表的两个查询,一个用于更新,另一个用于选择。

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

我真的希望 SQL Server 能够自己解决它。

【问题讨论】:

  • 最好的选择可能是调整你的查询,这样它们就不会互相死锁。您可以在问题中包含查询吗?
  • 问题是一个查询更新了另一个查询索引中使用的列。一个简单的 'select * from' 和一个从前一个选择更改非聚集索引中使用的任何列的更新都会死锁。
  • 锁定/阻塞可能是不可避免的,但这并不意味着无法避免死锁。在没有看到实际查询的情况下很难确定。
  • 只包括查询和死锁原因的简要说明。
  • 您在问题中提到了 2 个表,但查询中只引用了 1 个。

标签: sql-server sql-server-2008 deadlock isolation-level snapshot-isolation


【解决方案1】:

快照隔离是从等式中删除读取的非常可靠的解决方案。许多 RDBMS 始终启用它们。它们在实践中不会引起很多问题。更喜欢这种解决方案而不是一些手动脆弱的解决方案,例如非常具体的索引或提示。

【讨论】:

  • 我同意你的观点,但我很伤心,它可能会导致其他错误。
  • READ_COMMITTED_SNAPSHOT 很少会导致错误或问题。你需要设计案例来发现问题。它们确实存在,但它比一直担心读取查询中的不一致读取和死锁要糟糕得多。 SI 是一个非常好的通用解决方案。被低估了,因为默认情况下它是关闭的,而且很难理解。
  • 阅读更多关于快照隔离级别的信息我注意到存在一种不同类型的冲突,即更新冲突。这不是继续使用已提交读隔离级别的好理由吗?如何保证不会发生更新冲突?
  • 我通常推荐 SI 用于只读查询(不费吹灰之力)和保证不重叠数据的写入查询。在其他情况下,不同的隔离级别可能更合适。在你的问题中,我会让 SELECT 使用 SI。这将它排除在等式之外。
【解决方案2】:

请尝试在 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

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

【讨论】:

  • 问题是我需要修复每个使用相同索引的选择查询,并且任何其他开发人员都必须知道它。
猜你喜欢
  • 2019-07-11
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 2012-04-27
  • 2010-11-09
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多