加速无子句的巨大 DELETE FROM <table> 的方法

tus*_*eau 38 performance sql-server delete

使用 SQL Server 2005。

我正在执行一个没有 where 子句的巨大 DELETE FROM。它基本上等同于 TRUNCATE TABLE 语句 - 除了我不允许使用 TRUNCATE。问题是表很大 - 1000 万行,需要一个多小时才能完成。有没有办法让它更快,没有:

  • 使用截断
  • 禁用或删除索引?

t-log 已经在一个单独的磁盘上。

欢迎任何建议!

gbn*_*gbn 40

您可以做的是批量删除,如下所示:

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable
Run Code Online (Sandbox Code Playgroud)

例如,xxx 是 50000

对此的修改,如果您想删除非常高百分比的行...

SELECT col1, col2, ... INTO #Holdingtable
           FROM MyTable WHERE ..some condition..

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable WHERE ...

INSERT MyTable (col1, col2, ...)
           SELECT col1, col2, ... FROM #Holdingtable
Run Code Online (Sandbox Code Playgroud)

  • @tuseau:每次删除都需要一些日志空间,以防出错,以便回滚。50k 行删除比 10m 行删除占用更少的资源/空间。当然,日志备份仍然运行等等并占用空间,但在服务器上进行大量小批量备份比处理大批量更容易。 (3认同)
  • 谢谢,批量删除有点帮助,我想这是最好的选择。 (2认同)
  • @Phil Helmer:如果批量删除在事务中,那么使用它没有任何好处。否则,每次日志写入都较小,这很简单,加载更容易 (2认同)
  • 另一条评论:批量删除有很大帮助,删除 2000 万行的时间从 1 小时 42 分钟减少到 3 分钟——但要确保表有聚集索引!如果它是一个堆,则 TOP 子句在执行计划中创建一个排序,它否定任何改进。事后似乎很明显。 (2认同)
  • @Noumenon:它确保@@ROWCOUNT 为 1 (2认同)

SQL*_*tar 21

您可以使用 TOP 子句轻松完成此操作:

WHILE (1=1)
BEGIN
    DELETE TOP(1000) FROM table
    IF @@ROWCOUNT < 1 BREAK
END
Run Code Online (Sandbox Code Playgroud)


Jef*_*eff 7

如果您无法使用 TRUNCATE,我同意将您的删除批处理为可管理块的建议,并且我喜欢删除/创建建议的原创性,但我对您的问题中的以下评论感到好奇:

它基本上等同于 TRUNCATE TABLE 语句 -除了我不允许使用 TRUNCATE

我猜测此限制的原因与需要授予直接截断表的安全性以及它允许​​您截断除您关心的表之外的表有关。

假设是这种情况,我想知道创建一个使用 TRUNCATE TABLE 并使用“EXECUTE AS”的存储过程是否会被认为是提供直接截断表所需的安全权的可行替代方案。

希望这将为您提供所需的速度,同时还可以解决您的公司在将您的帐户添加到 db_ddladmin 角色时可能遇到的安全问题。

以这种方式使用存储过程的另一个优点是存储过程本身可以被锁定,以便只允许特定帐户使用它。

如果由于某种原因这不是一个可接受的解决方案并且您需要删除此表中的数据是需要每天/每小时/等完成一次的事情,我会请求创建一个 SQL 代理作业来截断表在每天的预定时间。

希望这可以帮助!


Mar*_*ian 5

除了 truncate.. 只有批量删除可以帮助你。

当然,您可以删除表并重新创建它,包括所有约束和索引。在 Management Studio 中,您可以选择编写要删除和创建的表的脚本,因此这应该是一个微不足道的选择。但这仅当您被允许执行 DDL 操作时,我认为这不是一个真正的选择。