T-SQL方法可以避免基于子查询结果更新同一行

时间:2016-10-21 18:17:05

标签: sql sql-server database locking

我有一个带有记录(原始电子邮件)的SQL Server表,需要由外部进程(邮件程序)按给定顺序处理(构建电子邮件并发送它)。它不是非常耗费资源,但可能需要一段时间才能解决所有分析和SMTP开销等问题。

为了加快速度,我可以轻松地在多台服务器上运行多个邮件程序实例,但担心如果两台服务器几乎同时启动,它们可能仍会重叠并发送相同的记录。

简化问题,我的表看起来像这样,每条记录都有电子邮件的数据。

queueItem
======================
  queueItemID PK
  ...data...
  processed bit
  priority int
  queuedStart datetime
  rowLockName varchar
  rowLockDate datetime

第1批(服务器1

  • 从中午12:00开始
  • 锁定/保留前5000行(1-5000)
  • 选择新保留的行
  • 开始工作

第2批(服务器2

  • 从下午12:15开始
  • 锁定/保留接下来的5000行(5001-10000)
  • 选择新保留的行
  • 开始工作

要锁定我一直使用以下内容的行:

declare @lockName varchar(36)
set @lockName = newid()
declare @batchsize int
set @batchsize = 5000

update queueItem
  set rowLockName = @lockName,
  rowLockDate = getdate()
where queueitemID in (
  select top(@batchsize) queueitemID 
  from queueItem
  where processed = 0
  and rowLockName is null
  and queuedStart <= getdate()
  order by priority, queueitemID 
)

如果我没弄错,查询将首先开始执行 SELECT 子查询,然后锁定行以准备 update ,这很快但不是即时的。

我担心的是,如果我几乎在同一时间开始两批(比子查询运行得快)批处理1的更新可能无法完成,批处理2的SELECT 将会看到记录仍然可用并尝试/成功覆盖第1批(种类条件?)

我已经进行了一些测试,但到目前为止还没有与它们重叠的问题,它是否会在最糟糕的时候困扰我?

也许有更好的方式来编写这个值得研究的查询,因为我不是一个T-SQL大师。

0 个答案:

没有答案