【问题标题】:How can I reduce transaction log usage when deleting from a massive table in SQL Server?从 SQL Server 中的海量表中删除时,如何减少事务日志的使用?
【发布时间】:2013-10-03 20:39:36
【问题描述】:

我有这个功能,可以从超过 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 来强制数据库每次都进行这些更改。

【问题讨论】:

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


    【解决方案1】:

    您应该使用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。

    【讨论】:

    • 好的,现在计划使用偷偷摸摸的方法。我正在使用简单的恢复模式,因此没有进行备份,但我想通过数千次删除收费会在事务日志中创建很多内容,并且有时需要自行清除。所以也许等待延迟可以解决这个问题。
    • 我有一个问题。我只看到为一张表删除大量行的示例。如果我需要从 6 个表中删除数百万条记录怎么办。这种“10000”方式有效吗?还是我必须单独处理?
    【解决方案2】:

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

    【讨论】:

    • 这个数据库的正常恢复模式已经很简单了,但是在删除几百万行时它仍然会爆炸到 250GB:/ 怎么样,我仍然不确定
    【解决方案3】:

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

    CHECKPOINT 1;

    每 N 次迭代后释放日志的命令。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2018-01-03
        • 2010-09-08
        • 2017-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-26
        • 2011-12-08
        • 1970-01-01
        相关资源
        最近更新 更多