从SQL Server中的大型表中删除时,如何减少事务日志的使用?

时间:2011-03-10 15:13:43

标签: sql sql-server sql-server-2005 tsql

我有这个功能删除了一个超过1000万行的大表中不再需要的历史数据

DELETE FROM BigTable
WHERE DATEDIFF(month,dtmtimestamp, getdate()) > 2)

然后我尝试使用此方法来减少事务日志使用的空间量:

WHILE (SELECT COUNT(*) FROM BigTable WHERE DATEDIFF(month,dtmtimestamp, getdate()) > 2) > 0 BEGIN
    DELETE TOP 10000 FROM BigTable
    FROM BigTable
    WHERE DateDiff(month,dtmtimestamp, getdate()) > 2
CONTINUE END 

这是正确的方法吗?或者我会以这种方式使用更多的事务日志?

有什么好方法的提示吗?

干杯,
尼科

最终答案

DECLARE @Remainder INT
DECLARE @ChunkSize INT
SET @Remainder = (SELECT COUNT(id) FROM BigTable WHERE dtmtimestamp < DateAdd(month, -2, getdate()))
SET @ChunkSize = CEILING(@Remainder/100) /* Divide the total into 100 parts, whole integers only */
WHILE @Remainder BEGIN
    BEGIN TRANSACTION deletehistorical
    DELETE TOP (@ChunkSize)
    FROM BigTable
    WHERE dtmtimestamp < DateAdd(month, -2, getdate());
    SET @Remainder = @@ROWCOUNT;
    COMMIT TRANSACTION deletehistorical
END

CHECKPOINT命令只告诉引擎从日志中删除已完成的事务(在简单恢复模式下),并且由于此查询实际上仍然继续执行每个循环,因此仍在创建事务。因此,为了分解事务,我添加了一个BEGIN和COMMIT来强制数据库每次都进行这些更改。

4 个答案:

答案 0 :(得分:4)

不是计算仍要删除的行数,而是应该使用EXISTS(所以只要找到一行就会返回):

WHILE EXISTS(SELECT * FROM BigTable WHERE DATEDIFF(month,dtmtimestamp, getdate()) > 2) BEGIN

或偷偷摸摸:

select top 1 * from sysobjects /* Force @@ROWCOUNT > 0 */
WHILE @@ROWCOUNT BEGIN
    DELETE TOP 10000 FROM BigTable
    FROM BigTable
    WHERE dtmtimestamp< DateAdd(month, -2,getdate())
CONTINUE END

表中唯一的搜索是用于执行实际删除的搜索。

如果dtmtimestamp列有一个有用的索引,我也会移动你的日期逻辑。

编辑当然,正如Martin指出的那样,这些都不能解决事务日志的使用问题。

限制删除的策略是一个合理的策略来阻止可怕的日志使用,但是还需要同时进行大量的日志备份或截断,以允许重用旧的事务日志空间。否则,它仍然会增加日志。

如果你知道每15分钟发生一次日志备份,你可能希望每隔“n”次迭代暂停一次循环,使用WAITFOR DELAY,这样你就知道之前的事务日志使用已经备份/清除。无论发生什么,只要您删除而不是截断,每个已删除行的日志记录仍将占用日志或日志备份中的空间。

如果您能够通过离线使用此系统正常运行的任何内容,并且要保留的行数量与要删除的行相比相形见绌,您可能希望将行复制到另一个表中,删除所有外键,截断表,复制保留的行,然后重建外键。 YMMV。

答案 1 :(得分:1)

将恢复模式更改为数据库的简单模式,进行更新/删除,然后更改回以前的恢复模式。

答案 2 :(得分:1)

由于您的数据库处于简单恢复状态,因此请解决您的脚本问题

CHECKPOINT 1;

每次N次迭代后

命令释放日志。

答案 3 :(得分:0)

在简单恢复模式下,如果日志变为70%已满,则自动检查点将排队。 限制db属性中的最大日志文件大小将阻止日志文件超出范围。