【发布时间】:2019-11-06 14:05:34
【问题描述】:
我正在使用循环来删除多个块中的行。
WHILE EXISTS (SELECT 1 FROM dbo.Table WHERE LogTime < CAST('2018-11-05' AS
DATE))
BEGIN
BEGIN TRANSACTION T1
DELETE TOP (1000) FROM dbo.Table
WHERE LogTime < CAST('2018-11-05' AS date);
COMMIT;
END
我希望每个 While 循环周期都是一个以“COMMIT”结尾的事务,因此在每个循环周期后都会清理事务日志。
不幸的是,情况并非如此。在 15 分钟后的某个时刻,查询由于“事务日志已满”而崩溃。然后开始回滚,不仅回滚最后一个循环周期,而且回滚整个查询,包括所有其他循环周期。
【问题讨论】:
-
日志不是这样工作的。在 FULL 模式下,日志记录会一直保留到日志备份为止。如果崩溃将所有内容回滚,则意味着您有 另一个 整体事务,因此即使在 SIMPLE 模式下也不会删除任何内容。 SQL Server 没有嵌套事务,因此外部事务是唯一重要的事务。提交内部事务不会做任何事情。 ROLLBACK 将回滚所有内容
-
如果您经常批量删除,您应该使用表分区并使用
TRUNCATE TABLE Imagination_Partitioned WITH (PARTITIONS(@partition))截断不需要的分区。自 SQL Server 2016 SP1 以来的所有版本(甚至 Express)都提供分区,并且鉴于 2016 是最旧的受支持版本,所有受支持的版本 -
文章How to Partition SQL Server Tables and Truncate Partitions 解释了分区并包含一个有趣的示例,包括一个根据日期计算要截断哪些分区的方法
-
您可以在事后创建分区,尽管随着数据的移动需要一段时间。分区方案取决于您的 要求 - 有多少行,您要删除多少数据以及多久删除一次?您还可以在具有相同架构的表之间切换分区(这只是元数据操作,几乎是即时的),这意味着您可以在截断分区之前将数据移动到历史表
-
那时你还没有阅读我的评论。不,那不是真的。事实上,受支持的版本是 100% 错误的。
Partitions are available in all editions (even Express) since SQL Server 2016 SP1 and given that 2016 is the oldest supported version, all supported versions其他随处可用的功能是“异国情调”,如列存储索引、压缩和内存表。您可能不需要删除任何数据,只需对其进行压缩或使用列存储
标签: sql-server transactions sql-delete