8

假设我有一个包含 10000000 条记录的表。这两种解决方案有什么区别?

  1. 删除数据,例如:

    DELETE FROM MyTable
    
  2. 逐行删除应用程序的所有数据:

    DELETE FROM MyTable WHERE ID = @SelectedID
    

第一个解决方案是否具有最佳性能?对日志和性能有什么影响?

4

7 回答 7

22

如果您需要限制需要删除的行而不是完全删除,或者您不能使用 TRUNCATE TABLE(例如,该表被 FK 约束引用,或者包含在索引视图中),那么您可以这样做分块删除:

DECLARE @RowsDeleted INTEGER
SET @RowsDeleted = 1

WHILE (@RowsDeleted > 0)
    BEGIN
        -- delete 10,000 rows a time
        DELETE TOP (10000) FROM MyTable [WHERE .....] -- WHERE is optional
        SET @RowsDeleted = @@ROWCOUNT
    END

一般来说,TRUNCATE 是最好的方法,如果可能的话我会使用它。但它不能在所有场景中使用。另外,请注意 TRUNCATE 将重置表的 IDENTITY 值(如果有)。

如果您使用的是 SQL 2000 或更早版本,则 TOP 条件不可用,因此您可以改用 SET ROWCOUNT。

DECLARE @RowsDeleted INTEGER
SET @RowsDeleted = 1
SET ROWCOUNT 10000 -- delete 10,000 rows a time

WHILE (@RowsDeleted > 0)
    BEGIN
        DELETE FROM MyTable [WHERE .....] -- WHERE is optional
        SET @RowsDeleted = @@ROWCOUNT
    END
于 2010-01-26T10:12:32.460 回答
14

如果您的表中有那么多记录并且您想将它们全部删除,您应该考虑truncate <table>使用delete from <table>. 它会快得多,但请注意它无法激活触发器。

有关详细信息,请参阅(本例 sql server 2000):http: //msdn.microsoft.com/en-us/library/aa260621%28SQL.80%29.aspx

逐行删除应用程序中的表将在很长一段时间内结束,因为您的 dbms 无法优化任何内容,因为它事先不知道您将删除所有内容。

于 2010-01-26T09:57:34.293 回答
3

第一个显然具有更好的性能。

当您指定 DELETE [MyTable] 时,它将简单地删除所有内容而不检查 ID。第二个将浪费时间和磁盘操作来定位相应的记录,然后再删除它。

它也变得更糟,因为每次记录从表中间消失时,引擎可能希望将数据压缩到磁盘上,从而浪费时间并再次工作。

也许更好的主意是按降序删除基于聚集索引列的数据。那么表基本上会在每次删除操作时从末尾截断。

于 2010-01-26T09:53:33.913 回答
3

选项 1 将创建一个非常大的事务并对日志/性能产生很大影响,以及升级锁以使表不可用。选项 2 会更慢,尽管它对日志的影响较小(假设为 bulk / full 模式)

如果您想删除所有数据,Truncate Table MyTable 会比两者都快,尽管它没有过滤行的功能,但它在后面进行元数据更改,并且基本上将 IAM 放在表的地板上问题。

于 2010-01-26T09:56:40.990 回答
2

清理表的最佳性能将带来TRUNCATE TABLE MyTable。有关更详细的解释,请参阅http://msdn.microsoft.com/en-us/library/ms177570.aspx

于 2010-01-26T09:57:24.293 回答
1

在 Microsoft TechNet 上找到这篇文章。

基本上,它建议:

  1. 通过使用 SELECT INTO,将要保留的数据复制到中间表;
  2. 截断源表;
  3. 使用 INSERT INTO 从中间表复制回来,将数据复制到源表;

..

BEGIN TRANSACTION

SELECT  *
   INTO    dbo.bigtable_intermediate
   FROM    dbo.bigtable
   WHERE   Id % 2 = 0;

   TRUNCATE TABLE dbo.bigtable;  

   SET IDENTITY_INSERT dbo.bigTable ON;
   INSERT INTO dbo.bigtable WITH (TABLOCK) (Id, c1, c2, c3)
   SELECT Id, c1, c2, c3 FROM dbo.bigtable_intermediate ORDER BY Id;
   SET IDENTITY_INSERT dbo.bigtable OFF;
ROLLBACK TRANSACTION
于 2014-09-03T20:10:36.087 回答
0

第一个将从表中删除所有数据,并且将比您的第二个仅删除特定键中的数据具有更好的性能。

现在,如果您必须从表中删除所有数据并且您不依赖使用回滚,请考虑使用截断表

于 2010-01-26T09:58:03.857 回答