删除sql server中的大量数据

时间:2010-01-26 09:50:22

标签: sql-server performance sql-delete

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

  1. 删除数据:

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

    DELETE FROM MyTable WHERE ID = @SelectedID
    
  3. 第一种解决方案是否具有最佳性能? 对日志和性能有什么影响?

7 个答案:

答案 0 :(得分:21)

如果您需要限制需要删除的行而不进行完全删除,或者您不能使用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

答案 1 :(得分:14)

如果您的表格中有这么多记录,而您想要全部删除这些记录,则应考虑truncate <table>而不是delete from <table>。它会快得多,但要注意它不能激活触发器。

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

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

答案 2 :(得分:3)

第一个明显有更好的表现。

当你指定DELETE [MyTable]时,它只会删除所有内容而不会检查ID。第二个将浪费时间和磁盘操作来每次删除它之前找到相应的记录。

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

也许更好的想法是按降序删除基于聚簇索引列的数据。然后在每次删除操作时,表格基本上都会被截断。

答案 3 :(得分:3)

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

如果你想摆脱所有数据,Truncate Table MyTable将比两者都快,虽然它没有过滤行的工具,它在后面做了元数据更改并且基本上放弃了IAM在地板上有问题的表格。

答案 4 :(得分:2)

清除表格的最佳效果会带来TRUNCATE TABLE MyTable。有关更详细的解释,请参阅http://msdn.microsoft.com/en-us/library/ms177570.aspx

答案 5 :(得分:0)

第一个会从表格中删除所有数据,并且会有更好的表现,即您的第二个人只会删除来自特定密钥的数据

现在,如果您必须删除表中的所有数据而不依赖于使用回滚,请考虑使用truncate table

答案 6 :(得分:0)

找到此post on Microsoft TechNet

基本上,它建议:

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

    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