【问题标题】:How-To delete 8,500,000 Records from one table on sql server如何从 sql server 上的一个表中删除 8,500,000 条记录
【发布时间】:2010-01-17 21:34:45
【问题描述】:

删除活动 其中 unt_uid 为空

将是最快的方法,但在此语句完成之前没有人可以访问数据库/表,所以这是不行的。

我定义了一个光标来在工作时间完成这项任务,但无论如何这对生产力的影响很大。 那么如何删除这些记录,保证这个数据库的正常使用呢?

它是 32 位 Win2003 上的 SQL-2005 服务器。第二个问题是:您预计完成这项工作需要多长时间(6 小时或 60 小时)? (是的,我知道这取决于负载,但假设这是一个小型企业环境)

【问题讨论】:

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


    【解决方案1】:

    您可以分块进行。例如,每 10 秒执行一次:

    delete from activities where activityid in 
      (select top 1000 activityid from activities where unt_uid is null)
    

    显然定义对您的应用程序最有意义的行数(我随意选择了 1000)和间隔(我选择了 10 秒)。

    【讨论】:

    • 感谢您的提示。我会用一个选择前 1000 个的光标来做,然后用一段时间 (select count(*) ...) > 0 包装它。我认为事务日志是另一个故事:不可能删除不记录而定期记录数据库的正常使用?
    • @ice 我不这么认为。您可以关闭日志以进行批量更新但不能删除。
    【解决方案2】:

    也许您可以创建一个新的相同表,插入要保留的记录,然后重命名表,以便新表替换旧表,而不是从表中删除记录。这仍然需要一些时间,但您网站上的停机时间会非常短(仅在交换表格时)

    【讨论】:

      【解决方案3】:

      我猜谁可以访问该表取决于您的事务隔离模式。

      但是,您大体上是对的 - 大量删除是不好的,特别是如果您的 where 子句意味着它不能使用索引 - 这意味着数据库可能无法只锁定它需要删除的行,所以它最终会在整个桌子上占据一个大锁。

      我最好的建议是重新设计您的应用程序,这样您就不需要删除这些行或任何行。

      您可以通过对表进行分区来完成此操作,以便您可以简单地删除分区,或者使用其他人建议的“复制要保留的行然后删除表”配方。

      【讨论】:

      【解决方案4】:

      我会使用“蚕食删除”技术。来自http://sqladvice.com/blogs/repeatableread/archive/2005/09/20/12795.aspx

      DECLARE @target int
      SET @target = 2000
      DECLARE @count int
      SET @count = 2000
      
      WHILE @count = 2000 BEGIN
      
       DELETE FROM myBigTable
       WHERE targetID IN
       (SELECT TOP (@target) targetID
        FROM myBigTable WITH(NOLOCK)
        WHERE something = somethingElse) 
      
       SELECT @count = @@ROWCOUNT
       WAITFOR DELAY '000:00:00.200'
      
      END
      

      我已经将它用于这种类型的场景。 WAITFOR 很重要,它允许其他查询在删除之间完成它们的工作。

      【讨论】:

      • 你不应该检查@count <> 0吗?否则,如果行数与 2000 不均分,您可能会剩下几行
      • 它确实有效。考虑最后一个 DELETE 是 1337 行的情况。 SELECT @count = @@rowcount 将得到 1337,终止 while 循环。
      • 当然,如果有任何触发器或级联删除,@@rowcount 将关闭。
      • 总的来说,这不是一个坏主意。但它有点像一个黑匣子。您应该先以小组的形式进行,以了解每个“啃”所需的时间。
      • 是的,你必须计算出每个半字节的大小。太大了,你会把每个人都锁在外面。太小,您在 WAITFOR 中花费的时间太多。
      【解决方案5】:

      在小型企业环境中,您需要在标准操作行为中删除 500,000 行而不影响任何其他用户,这似乎很奇怪。通常对于这么大的删除,我们会创建一个新表并使用 TRUNCATE/INSERT 或 sp_rename 覆盖旧表。

      话虽如此,在特殊情况下,如果我的一个每月进程检测到它需要重新运行生成这 2 亿行的进程,它可以定期删除 2 亿行,每次大约 3 百万行。但这是专用数据仓库数据库中的单用户进程,我不会称其为小企业场景。

      我支持建议为您的设计寻找替代方法的答案。

      【讨论】:

        【解决方案6】:

        我会为此创建一个任务并安排它在非高峰时间运行。但我不建议您在正在使用的表中删除。将要保留的行移动到新表中,并完全删除当前表以及要删除的许多行。

        【讨论】:

        猜你喜欢
        • 2011-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-30
        • 2018-12-01
        • 2021-11-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多