Tom*_*int 4 sql-server sql-server-2016
在过去的几天里,我一直在尝试编写一个自动过程的查询,该过程将在指定的日期范围(一个月)内将日志表中的记录删除到另一个表中,然后可以将它们转储到磁盘和记录从数据库中删除。第一种,天真的方法,ala
DELETE FROM <sometable>
OUTPUT DELETED.* INTO [<sometable>_{year}_{month}]
WHERE DATEPART(YEAR, [DateTime]) = {year} AND DATEPART(MONTH, [DateTime]) = {month}
Run Code Online (Sandbox Code Playgroud)
当然炸毁了交易日志。然后我尝试做同样的事情,但现在批量为 1m 行,如下所示
WHILE @@ROWCOUNT > 0
BEGIN
DELETE TOP (1000000) FROM <sometable>
OUTPUT DELETED.* INTO [<sometable>_{year}_{month}]
WHERE DATEPART(YEAR, [DateTime]) = {year} AND DATEPART(MONTH, [DateTime]) = {month}
END
Run Code Online (Sandbox Code Playgroud)
但这并没有改变事务日志的增长。接下来,我尝试在循环中使用显式事务。
WHILE @@ROWCOUNT > 0
BEGIN
BEGIN TRAN
DELETE TOP (1000000) FROM <sometable>
OUTPUT DELETED.* INTO [<sometable>_{year}_{month}]
WHERE DATEPART(YEAR, [DateTime]) = {year} AND DATEPART(MONTH, [DateTime]) = {month}
COMMIT
END
Run Code Online (Sandbox Code Playgroud)
再次。没有不同。更糟糕的是,如果我取消此查询并执行 ROLLBACK 以释放表,它会回滚所有内容。正如人们所期望的那样,不仅仅是最后一次迭代,而是整个过程。为什么循环中的各个事务没有被这样对待?当然,必须有一种方法可以在数据库中移动大量行,而 SQL 不会发出嘶嘶声并炸毁它的用户吗?
这里的关键是:
更糟糕的是,如果我取消此查询并执行 ROLLBACK 以释放表,它会回滚所有内容。正如人们所期望的那样,不仅仅是最后一次迭代,而是整个过程。
所以显然你的工作已经受到交易保护。将其分解为几个 DELETE 并没有为您注意,因为显然它们仍然是一笔交易。你需要找出原因。您不会说从哪里执行代码。
如果您使用 SSMS,那么也许有人打开了 SET IMPLICIT_TRANSACTIONS ON。这将关闭自动提交。可以在 SSMS 的配置选项中完成或使用上述命令。但是,您必须在完成后提交您的工作,否则 SSMS 会发现您有一个打开的事务并询问您是要提交还是回滚。
也许您使用其他一些环境来保护您的工作并在 SQL Server 抛出异常时提交回滚。这就是我要开始的地方。这可以解释一切 - 但你身边还有一些挖掘工作要做。