如何在不让日志文件失控的情况下从巨大的表中删除过期数据?

Posted

技术标签:

【中文标题】如何在不让日志文件失控的情况下从巨大的表中删除过期数据?【英文标题】:How can I delete expired data from a huge table without having the log file grow out of control? 【发布时间】:2011-08-20 23:51:50 【问题描述】:

我有一个巨大的表(30 亿行),不幸的是其中包含大部分过期数据。我想简单地删除所有这些过期的行,并保留其余的。

我可以执行这样的语句:

delete from giganticTable where exp_date < getDate()

执行计划以某种方式估计将删除大约 4 亿行。

执行时,不仅一个小时后没有完成,而且数据库事务日志文件也从 6 GB 增长到 90 GB。请注意,发生这种情况时,数据库处于批量日志恢复模式。我最终取消了这个查询,因为我确信一定有更好的方法来做到这一点。

我有几个表需要执行类似的操作。如果我完全不想恢复它们,那么删除这些行的最快和最节省空间的方法是什么?

请注意,我使用的是 Microsoft SQL Server 2005。

【问题讨论】:

【参考方案1】:

我发现从具有大量行的表中删除以批量删除行(例如 5000 左右)很有用(我通常测试哪个值工作最快,有时是 5000 行,有时是 10,000 行,等等。)。这样可以让每个删除操作快速完成,而不是等待很长时间让一条语句敲出 4 亿条记录。

在 SQL Server 2005 中,这样的东西应该可以工作(当然,请先测试):

WHILE EXISTS ( SELECT * FROM giganticTable WHERE exp_date < getDate())
BEGIN
  DELETE TOP(5000) FROM giganticTable WHERE exp_date < getDate()
END

我会看到批量删除对日志文件大小的影响。如果它仍然炸毁日志,那么您可以尝试将恢复模式更改为Simple,删除记录,然后切换回批量记录,但前提是系统可以容忍丢失一些最近的数据。在尝试该过程之前,我肯定会进行完整备份。这个thread 还建议您可以设置一个作业来备份仅指定截断的日志,因此这可能是另一种选择。希望您有一个可以测试的实例,但我将从批量删除开始,看看它如何影响性能和日志文件大小。

【讨论】:

【参考方案2】:

当您想在表上做大量工作时,您真的不想尝试任何愚蠢的事情,例如关闭日志记录,因为长时间任务期间的任何问题都可能很容易导致数据库损坏和其他问题。不过,有办法解决您的问题。

创建一个与您的真实表的架构相匹配的临时表。用您想要保留的数据填充它。然后,截断原始表(在日志文件上非常快速和容易)。最后,将数据移出临时表并放入原始(现在为空)表中。

如果您使用自动递增的主键,则需要强制该字段采用您的原始键(这样您以后就不会遇到问题)。

【讨论】:

您是否见过任何仅更改恢复模型导致数据库损坏的实例? @rsbarro - 不只是更改恢复模式,不,但是当恢复模式设置不正确时,我已经看到数据库在一个大的过程中损坏(就像这样)。这会导致您丢失数据库。 我明白您的意思,但是将恢复模式设置为简单并不意味着您会丢失数据库。这只是意味着您只能恢复到上次的完整备份。我只是问,因为您的回答看起来好像只是切换恢复模式会导致损坏,我个人没有见过这种情况。 @rsbarro - 我明白你的意思。在重新阅读我所写的内容后,我发现我好像在说更改模型可能会导致损坏。我稍微修改了文本以使其更清晰。感谢您指出这一点。【参考方案3】:

你应该每天都做,所以你不会一次得到这么大的工作。 既然你处于这种情况,以下是我的建议:

    像 rsbarro 所说的那样拆分工作。您可能不需要 while 语句 - 您可以在几天内完成。

    明确地写日期,如:

    delete from giganticTable where exp_date < '2013-08-07'
    
    我对巨大的日志没有一个好主意,似乎没有什么好办法。

【讨论】:

以上是关于如何在不让日志文件失控的情况下从巨大的表中删除过期数据?的主要内容,如果未能解决你的问题,请参考以下文章

在一个巨大的表中处理删除/插入/选择

如何在不创建快照的情况下从 cassandra 表中删除所有记录

如何在不创建查询的情况下从 Access 表中获取值

无法在 Excel 崩溃的情况下从工作表中删除命令按钮

如何在不指定列名的情况下从另一个表更新一个表?

如何在不删除任何文件的情况下从跟踪中分离文件夹?