【问题标题】:Truncating Large Tables截断大表
【发布时间】:2018-10-17 22:47:53
【问题描述】:

我有一个包含 7 亿数据的表,以最快的方式清空该表的最佳方法是什么。我认为使用 delete 语句不适合此类操作,因为它会记录整个事务。

【问题讨论】:

标签: sql-server tsql database-administration


【解决方案1】:

我能看到的三种方式

  1. 截断表
  2. 用脚本编写表,然后删除表并使用脚本重新创建表。
  3. 假设表有PK,则创建一个类似的表,并使用partition switch in/out将表切换到新表,然后drop新创建的表。

欢迎为这个简单而有趣的问题提供更多想法。

【讨论】:

  • ALTER TABLE ... SWITCH 不需要 PK。
  • 切入/切出技巧在恕我直言,因为您可以按任何时间表处理“要丢弃的表”,无论您喜欢多么积极。
  • 用老式的方法来做。使用 CURSOR,一次一行。 (将此作为评论,以免有人将其误认为是认真的答案并投反对票;我需要积分)。
  • 感谢 David Browne 提醒您不需要 PK。我可能错了,但在 SQL Server 2005/8 天,我记得表需要有一个 PK。 @Stuart,你的评论让我笑了这么久,真的很欣赏幽默。
【解决方案2】:

正如你的标题所说 - 如果你正在寻找最快的方法,那么你应该截断表格。

TRUNCATE TABLE [dbo].[mytable]

截断表有the following advantages:

与DELETE语句相比,TRUNCATE TABLE有以下几点 优点:

  • 使用的事务日志空间更少。

DELETE 语句一次删除一行并记录一个条目 在每个已删除行的事务日志中。 TRUNCATE TABLE 删除 通过释放用于存储表数据的数据页来获取数据 并且只在事务日志中记录页面释放。

  • 通常使用较少的锁。

当使用行锁执行 DELETE 语句时,每一行在 该表被锁定以进行删除。 TRUNCATE TABLE 总是锁定 表(包括架构 (SCH-M) 锁)和页,但不是每一行。

  • 无一例外,表格中剩下零页。

在执行 DELETE 语句后,表仍然可以包含 空白页。例如,堆中的空页不能被释放 至少没有排他(LCK_M_X)表锁。如果删除 操作不使用表锁,表(堆)将包含 许多空白页。对于索引,删除操作可以留空 后面的页面,尽管这些页面将被快速释放 后台清理进程。

TRUNCATE TABLE 删除表中的所有行,但表结构 并且它的列、约束、索引等仍然存在。删除 表定义除了它的数据,使用 DROP TABLE 声明。

如果表包含标识列,则该列的计数器 重置为为列定义的种子值。如果没有种子 定义时,使用默认值 1。要保留身份计数器, 请改用 DELETE。

虽然截断也会重置标识,所以如果您需要保留它,您应该先获取标识符(从表中编写脚本),然后在截断后将表设置回该标识符。或者,您可以只编写表格的脚本,删除它并重新创建它。

或者,您可以使用以下命令轻松切换表数据

--May need to script out table if you have things like compression.
select TOP 0 * into mytable_old from mytable; 

ALTER TABLE mytable SWITCH TO mytable_old;

DROP TABLE mytable_old;

切换数据是一种元数据更改,实际上没有数据在磁盘上移动,因此这通常是一个相当快的(假设表上没有阻塞)操作和非常少的 I/O。删除表当然会像往常一样招致 I/O 惩罚。

最后 - 如果由于某种原因您在表上有 A BUNCH 锁,您可能希望慢慢地从表中删除记录。这并不快,但是当我使用它时,它会将阻塞保持在最低限度,因为删除窗口很快。不过,这会将更多信息写入日志,因此如果您有类似复制的内容,这可能会使日志读取器代理发疯,因为它将有太多记录需要处理(有关于解决方法的整个主题,但我我偏离了轨道)。话虽如此 - 这更像是一种特殊情况的删除,可能只应作为最后的手段使用(或者当您需要指定要删除的某些内容时)。

;WITH CTE AS
(
   select TOP 1000 *  -- Depending on the blocking, you may want to up/down this amount
   from mytable
)
delete from CTE;

WHILE (@@ROWCOUNT > 0)
BEGIN
   WAITFOR DELAY '00:00:03'; -- Gives times for other queries to process/helps with blocking

   ;WITH CTE AS
   (
     select TOP 1000 *
     from mytable
   )
   delete from CTE;
END

【讨论】:

  • Truncating does not write to the log 这是simply not true
  • 是的,抱歉 - 暂时没有考虑清楚(我真的知道你可以回滚截断,只是漫长的一天)。我修正了答案并扩展了它。
【解决方案3】:

如果您要从该表中删除所有行,那么最简单的选择是截断表,如下所示:

TRUNCATE TABLE TableName

参考:How to delete large data of table in SQL without log?

【讨论】:

    【解决方案4】:

    最好的方法是 TRUNCATE TABLE

    TRUNCATE TABLE [Schema].[TableName]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-02
      • 2020-04-11
      • 1970-01-01
      • 2016-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多