我有这个功能删除了一个超过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来强制数据库每次都进行这些更改。
答案 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;
命令释放日志。
答案 3 :(得分:0)
在简单恢复模式下,如果日志变为70%已满,则自动检查点将排队。 限制db属性中的最大日志文件大小将阻止日志文件超出范围。