【问题标题】:Parallel merge strategy without deadlock无死锁的并行合并策略
【发布时间】:2020-05-14 20:26:21
【问题描述】:

使用 SQL Server 2016,我希望通过包含在同一张表上的简单插入/更新/删除的简单过程将数据从 SourceTable 合并到 DestinationTable

SourceTable 由几个不同的应用程序填充,它们调用MergeOrders 存储过程将他们上传的行从SourceTable 合并到DestinationTable

MergeOrders 存储过程可以有多个实例并行运行。

我得到了很多锁,但这是正常的,问题是有时我会得到“行组死锁”,这是我无法承受的。

在这种并行环境中执行这种合并操作的最佳方式是什么。

我正在考虑 TABLOCK 或 SERIALIZABLE 提示,或者可能是应用程序锁来序列化访问,但如果有更好的方法感兴趣。

【问题讨论】:

  • DestinationTable 上还有其他索引吗?如果所有应用程序都使用一个 SourceTable,那么并行运行它可能没有意义,而应用程序锁是最简单的方法。

标签: sql-server merge sql-server-2016 database-deadlocks


【解决方案1】:

应用锁将序列化尝试运行此过程的会话。它应该是这样的:

create or alter procedure ProcWithAppLock 
with execute as owner
as
begin
  set xact_abort on;
  set nocount on;
  begin transaction;
  declare @lockName nvarchar(255) = object_name(@@procid) + '-applock';
  exec sp_getapplock @lockName,'Exclusive','Transaction',null,'dbo';


  --do stuff
  waitfor delay '00:00:10';
  select getdate() dt, object_name(@@procid);

  exec sp_releaseapplock @lockName, 'Transaction', 'dbo';
  commit transaction;
end

这个模板中有一些微妙的东西。首先,它没有 catch 块,并且在发生错误时依赖 xact_abort 来释放 applock。并且您希望显式释放应用程序锁,以防在长时间运行的事务的上下文中调用此过程。最后,锁的主体设置为dbo,这样非dbo 用户就不能获得冲突锁。这也要求使用execute as owner 运行该过程,因为应用程序用户通常不会是dbo

【讨论】:

  • 谢谢。我原来的 sp 已经使用 XACT_ABORT ON,但也有一个 CATCH 块来执行各种日志记录。它会导致任何故障吗?我想我会试试的。
  • 不,应该没问题。这不使用 TRY/CATCH 只是为了让它更简单一些。
  • 你提到我应该手动释放锁,如果 sp 运行时间更长(就是这种情况)。那我应该手动释放 CATCH 部分的锁吗?
  • 如果您强制回滚,则无需在 CATCH 中手动释放锁定。
猜你喜欢
  • 2018-09-08
  • 2016-01-12
  • 2020-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
  • 2012-11-14
  • 1970-01-01
相关资源
最近更新 更多