我需要更新我们的账户表以停用几个月来没有与我们开展业务的旧账户。我有一个包含 1704 个帐号的表,需要跨多个表停用这些帐号。一次运行所有更新时,花费的时间太长。
有没有一种方法可以让我逐一获取每个条目并提交交易,以便该帐户在我们的数据库中被列为已停用,然后再移动到下一个条目并重复,直到所有帐户都已更新?
我只尝试了一个典型的更新语句,这就是我遇到瓶颈的地方。我看过有关循环的建议,但它们都没有按照我正在寻找的方式运行。
这是可用于循环的代码框架:
CREATE TABLE #t_accs_to_deactivate (acc_id INT)
INSERT INTO #t_accs_to_deactivate
VALUES(1), (2), (4), (10)
SET XACT_ABORT ON;
DECLARE @acc_id INT
DECLARE cr_x CURSOR read_only forward_only local static FOR
SELECT acc_id
FROM #t_accs_to_deactivate
ORDER BY acc_id
OPEN CR_X
WHILE 1 = 1
BEGIN
FETCH NEXT FROM CR_X INTO @acc_id
IF @@FETCH_STATUS <> 0
BREAK
RAISERROR('Processing %d', 1, 1, @acc_id) WITH NOWAIT;
BEGIN TRAN
UPDATE t
SET active = 0
FROM table1 t
WHERE t.acc_id = @acc_id
AND active = 1
UPDATE t
SET active = 0
FROM table2 t
WHERE t.acc_id = @acc_id
AND active = 1
--- etc...
COMMIT TRAN;
END
CLOSE CR_X
DEALLOCATE CR_X
我通常会做一个 CURSOR 来选择一些表数据并逐一循环它。 在光标内,您可以执行更新和其他任何操作。
RAISERROR('Processing %d', 1, 1, @acc_id) WITH NOWAIT;
部分打印一条有关您已走了多远的信息消息。它比 PRINT 更好,因为 PRINT 有时会被缓冲并且不能及时显示。不过,RAISERROR 也可能发生这种情况。
我添加了
SET XACT_ABORT ON
以确保您的交易实际上因错误而完全中止。
如果需要,您可以使用
WAITFOR DELAY '00:00:15' -- 15 seconds
在循环中添加一点延迟,这允许其他人访问帐户。
注意死锁,多个表更新可能需要添加一些锁定提示。或者您可以将
SET DEADLOCK_PRIORTY LOW;
添加到脚本中,这样就不会过多干扰常规处理。
您可能需要将
OPTION(RECOMPILE)
添加到更新中,这样估算器就不会被伪造。此外,在某些情况下,删除 WHERE active = 1
可能会避免统计更新,这也可能会加快速度。