防止 SQL Server 中的死锁

2023-11-25

我有一个连接到 SQL Server 2014 数据库的应用程序,该数据库将多行合并为一行。当应用程序运行时,没有与此数据库的其他连接。

首先,选择特定时间跨度内的一组行。此查询使用与聚集查找合并的非聚集查找(TIME 列)。

select ...
from FOO
where TIME >= @from and TIME < @to and ...

然后,我们在 C# 中处理这些行,并将更改写入单个更新和多个删除,每个块会发生多次。这些也使用非聚集索引查找。

begin tran

update FOO set ...
where NON_CLUSTERED_ID = @id

delete FOO where NON_CLUSTERED_ID in (@id1, @id2, @id3, ...)

commit

当我使用多个并行块运行此程序时,我遇到了死锁。我尝试使用ROWLOCK为了update and delete但由于某种原因,这导致了比以前更多的死锁,即使块之间没有重叠。

然后我尝试了TABLOCKX, HOLDLOCK on the update,但这意味着我无法执行我的select并行,所以我失去了并行的优势。

知道如何避免死锁但仍然处理多个并行块吗?

使用起来安全吗NOLOCK on my select在这种情况下,假设块之间没有行重叠?然后TABLOCKX, HOLDLOCK只会阻止update and delete, 正确的?

或者我应该接受死锁的发生并在我的应用程序中重试查询?

UPDATE(附加信息):到目前为止,所有死锁都发生在update and delete阶段,没有一个select。如果我今天无法解决这个问题(之前未启用正确的跟踪标志),我将尝试获取一些死锁日志。

UPDATE:这是发生死锁的两种安排ROWLOCK,它们都仅指delete语句及其使用的非聚集索引。我不确定这些是否与没有任何表提示时发生的死锁相同,因为我无法重现其中任何一个。

Deadlock 1 Deadlock 2

询问 .xdl 是否还需要其他任何内容,我有点厌倦了附加整个内容。


关于死锁的一般建议:确保以相同的顺序执行所有操作,即针对不同的进程以相同的顺序获取锁。

您可以在 microsoft.com 上的这篇技术文章中找到相同的建议最大限度地减少死锁。它被列在第一位是有充分理由的。

  • 以相同的顺序访问对象。
  • 避免交易中的用户交互。
  • 保持交易简短且一批。
  • 使用较低的隔离级别。
  • 使用基于行版本控制的隔离级别。
  • 将 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON 以使读提交事务能够使用行版本控制。
  • 使用快照隔离。
  • 使用绑定连接。

卡托提出问题后更新:

在这里如何以相同的顺序获取锁?您对他如何更改 SQL 来做到这一点有什么建议吗?

无论什么环境,死锁总是相同的:两个进程(比如A & B)获取多个锁(比如X & Y)以不同的顺序,以便A正在等待Y and B正在等待X while A持有X and B持有Y.

它适用于此,因为DELETE and UPDATE语句隐式获取行或索引范围或表上的锁(取决于引擎认为合适的内容)。

您应该分析您的流程并查看是否存在可以以不同顺序获取锁的情况。如果这没有透露任何信息,您可以使用 SQL Server Profiler 分析死锁:

要跟踪死锁事件,请将死锁图事件类添加到跟踪。此事件类使用有关死锁中涉及的进程和对象的 XML 数据填充跟踪中的 TextData 数据列。 SQL Server Profiler 可以将 XML 文档提取到死锁 XML (.xdl) 文件中,您稍后可以在 SQL Server Management Studio 中查看该文件。您可以配置 SQL Server Profiler 将死锁图事件提取到包含所有死锁图事件的单个文件中,或者提取到单独的文件中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

防止 SQL Server 中的死锁 的相关文章

随机推荐