防止 SQL Server 中的死锁

新手上路,请多包涵

我有一个连接到 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 用于 updatedelete 但由于某种原因导致比以前更多的死锁,即使块之间没有重叠。

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

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

在这种情况下,考虑到块之间没有行重叠,在我的 select NOLOCK 是否安全?那么 TABLOCKX, HOLDLOCK 只会阻止 updatedelete ,对吗?

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

更新(附加信息):到目前为止,所有死锁都发生在 updatedelete 阶段,在 select 阶段没有发生。如果我今天不能解决这个问题,我会尝试获取一些死锁日志(之前没有启用正确的跟踪标志)。

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

死锁 1死锁 2

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

原文由 Jussi Kosunen 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 607
1 个回答

请在代码中以这种格式使用 get applock。存储过程 sp_getapplock 将锁放在应用程序资源上。

EXEC Sp_getapplock @Resource = ‘storeprocedurename’,@LockMode = ‘Exclusive’,@LockOwner = ‘Transaction’,@LockTimeout = 25000

这是非常有帮助的。请增加 LockTimeout 以减少死锁

原文由 Vishe 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进