Sql server 如何在没有日志的情况下删除SQL中表的大数据?

Sql server 如何在没有日志的情况下删除SQL中表的大数据?,sql-server,sql-server-2008,sql-optimization,Sql Server,Sql Server 2008,Sql Optimization,我有一个大数据表。 这个表中有1000万条记录 此查询的最佳方式是什么 Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE()) Delete LargeTable,其中readTime0) 开始 --一次删除少量行 删除顶部(10000)可调大容量 其中readTime0) 开始 开始交易 --一次删除少量行 删除顶部(10000)可调大容量 其中readTime0) 开始 开始交易 --一次删除少量行 删除顶部

我有一个大数据表。 这个表中有1000万条记录

此查询的最佳方式是什么

   Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())
Delete LargeTable,其中readTime
  • 如果要删除该表中的所有行,最简单的选项是截断该表,如

     TRUNCATE TABLE LargeTable
     GO
    
  • Truncate table只会清空该表,不能使用WHERE子句限制要删除的行,并且不会触发任何触发器

  • 另一方面,如果要删除80-90%以上的数据,比如说,如果总共有1100万行,并且要删除1000万行,另一种方法是将这100万行(要保留的记录)插入到另一个暂存表中。截断这个大表,然后将这100万行插回

  • 或者,若权限/视图或将此大型表作为其基础表的其他对象不受删除此表的影响,则可以将这些相对较少的行放入另一个表中,删除此表并创建具有相同架构的另一个表,然后将这些行重新导入此ex-large表中

  • 我能想到的最后一个选项是将数据库的
    恢复模式更改为SIMPLE
    ,然后使用while循环以较小的批量删除行,如下所示:

     DECLARE @Deleted_Rows INT;
     SET @Deleted_Rows = 1;
    
    
     WHILE (@Deleted_Rows > 0)
       BEGIN
        -- Delete some small number of rows at a time
          DELETE TOP (10000)  LargeTable 
          WHERE readTime < dateadd(MONTH,-7,GETDATE())
    
       SET @Deleted_Rows = @@ROWCOUNT;
     END
    
    DELETE TOP (10000)  LargeTable 
    WHERE readTime < dateadd(MONTH,-7,GETDATE())
    WHILE @@ROWCOUNT > 0
    BEGIN
        DELETE TOP (10000)  LargeTable 
        WHERE readTime < dateadd(MONTH,-7,GETDATE())
    END
    
    声明@Deleted\u行INT;
    设置@Deleted_Rows=1;
    而(@Deleted_Rows>0)
    开始
    --一次删除少量行
    删除顶部(10000)可调大容量
    其中readTime

  • 不要忘了将恢复模式改回完整模式,我认为您必须进行备份以使其完全有效(更改或恢复模式)。

    如果您愿意(并且能够)实施分区,这是一种有效的技术,可以在运行时开销很小的情况下删除大量数据。不过,一次性操作并不划算。

    @m-ali的答案是正确的,但也要记住,如果不在每个块之后提交事务并执行检查点,日志可能会增长很多。我将这样做,并将本文作为参考,包括性能测试和图表:

    DECLARE @Deleted_Rows INT;
    SET @Deleted_Rows = 1;
    
    
    WHILE (@Deleted_Rows > 0)
      BEGIN
    
       BEGIN TRANSACTION
    
       -- Delete some small number of rows at a time
         DELETE TOP (10000)  LargeTable 
         WHERE readTime < dateadd(MONTH,-7,GETDATE())
    
         SET @Deleted_Rows = @@ROWCOUNT;
    
       COMMIT TRANSACTION
       CHECKPOINT -- for simple recovery model
    END
    
    声明@Deleted\u行INT;
    设置@Deleted_Rows=1;
    而(@Deleted_Rows>0)
    开始
    开始交易
    --一次删除少量行
    删除顶部(10000)可调大容量
    其中readTime
    这个M.Ali的变体对我来说很好。它删除一些,清除日志并重复。我看着原木生长,掉落,然后重新开始

    DECLARE @Deleted_Rows INT;
    SET @Deleted_Rows = 1;
    WHILE (@Deleted_Rows > 0)
      BEGIN
       -- Delete some small number of rows at a time
        delete top (100000) from InstallLog where DateTime between '2014-12-01' and '2015-02-01'
        SET @Deleted_Rows = @@ROWCOUNT;
        dbcc shrinkfile (MobiControlDB_log,0,truncateonly);
    END
    

    @弗朗西斯科·戈登斯坦,只是轻微的修正。必须在设置变量后使用提交,否则WHILE将只执行一次:

    DECLARE @Deleted_Rows INT;
    SET @Deleted_Rows = 1;
    
    WHILE (@Deleted_Rows > 0)
    BEGIN
        BEGIN TRANSACTION
    
        -- Delete some small number of rows at a time
        DELETE TOP (10000)  LargeTable 
        WHERE readTime < dateadd(MONTH,-7,GETDATE())
    
        SET @Deleted_Rows = @@ROWCOUNT;
    
        COMMIT TRANSACTION
        CHECKPOINT -- for simple recovery model
    
    END
    
    声明@Deleted\u行INT;
    设置@Deleted_Rows=1;
    而(@Deleted_Rows>0)
    开始
    开始交易
    --一次删除少量行
    删除顶部(10000)可调大容量
    其中readTime
    您还可以使用GO+执行同一查询的次数

    DELETE TOP (10000)  [TARGETDATABASE].[SCHEMA].[TARGETTABLE] 
    WHERE readTime < dateadd(MONTH,-1,GETDATE());
    -- how many times you want the query to repeat
    GO 100
    
    DELETE TOP(10000)[TARGETDATABASE].[SCHEMA].[TARGETTABLE]
    其中readTime
    您可以使用while循环删除小批量,如下所示:

     DECLARE @Deleted_Rows INT;
     SET @Deleted_Rows = 1;
    
    
     WHILE (@Deleted_Rows > 0)
       BEGIN
        -- Delete some small number of rows at a time
          DELETE TOP (10000)  LargeTable 
          WHERE readTime < dateadd(MONTH,-7,GETDATE())
    
       SET @Deleted_Rows = @@ROWCOUNT;
     END
    
    DELETE TOP (10000)  LargeTable 
    WHERE readTime < dateadd(MONTH,-7,GETDATE())
    WHILE @@ROWCOUNT > 0
    BEGIN
        DELETE TOP (10000)  LargeTable 
        WHERE readTime < dateadd(MONTH,-7,GETDATE())
    END
    
    删除顶部(10000)可调大容量
    其中readTime0
    开始
    删除顶部(10000)可调大容量
    其中readTime
    另一个用途:

    SET ROWCOUNT 1000 -- Buffer
    
    DECLARE @DATE AS DATETIME = dateadd(MONTH,-7,GETDATE())
    
    DELETE LargeTable  WHERE readTime < @DATE
    WHILE @@ROWCOUNT > 0
    BEGIN
       DELETE LargeTable  WHERE readTime < @DATE
    END
    SET ROWCOUNT 0
    
    我能够在几分钟内从2100万行的表格中删除1900万行。这是我的方法

    如果此表上有一个自动递增主键,则可以使用此主键

  • 获取大表主键的最小值,其中readTime
  • 将主键>min_primary的所有行插入临时表(如果行数不大,则插入内存表)

  • 放下那张大桌子

  • 重新创建表格。将所有行从临时表复制到主表

  • 放下暂存表

  • 简短语法

    select 1
    WHILE (@@ROWCOUNT > 0)
    BEGIN
      DELETE TOP (10000) LargeTable 
      WHERE readTime < dateadd(MONTH,-7,GETDATE())
    END
    
    选择1
    而(@@ROWCOUNT>0)
    开始
    删除顶部(10000)可调大容量
    其中readTime
    如果您使用的是SQL server 2016或更高版本,并且如果您的表具有基于您尝试删除的列(例如Timestamp列)创建的分区,则可以使用此新命令按分区删除数据

    用(分区({}[,…n]))截断表。

    这将只删除选定分区中的数据,并且应该是从表的一部分中删除数据的最有效方法,因为它不会创建事务日志,并且将以与常规截断相同的速度完成,但不会从表中删除所有数据

    缺点是,如果您的表没有使用分区进行设置,那么您需要重新开始使用常规方法删除数据,然后使用分区重新创建表,以便将来可以这样做,这就是我所做的。我将分区创建和删除添加到插入过程本身中。我的表有5亿行,所以这是减少删除时间的唯一选择

    有关更多详细信息,请参阅以下链接:

    下面是我首先删除dat的步骤
     IsRepeat:
        DELETE TOP (10000)
        FROM <TableName>
        IF @@ROWCOUNT > 0
             GOTO IsRepeat