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

我有一个大的数据表。 这张表有1000万条logging。

这个查询的最佳方法是什么?

Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE()) 
  1. 如果您正在删除该表中的所有行,最简单的select是截断表,就像

     TRUNCATE TABLE LargeTable GO 

    截断表将简单地清空表,您不能使用WHERE子句来限制被删除的行,并且不会触发任何触发器。

  2. 另一方面,如果你删除了超过80-90%的数据,比如说你总共有1100万行,而你想以另一种方式删除1000万行,那么插入这100万行(logging要保留)到另一个登台表。 截断这个大表,然后插入这100万行。

  3. 或者,如果拥有这个大型表作为其基础表的权限/视图或其他对象不会因为删除此表而受到影响,那么可以将这些相对较less的行放到另一个表中,然后使用相同的模式创build另一个表并导入这些表回到这个ex-Large表。

  4. 我能想到的最后一个select是将数据库的Recovery Mode to SIMPLE更改Recovery Mode to 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 

并且不要忘记将恢复模式改回到完全的状态,我想你必须进行备份才能使其完全有效(更改或恢复模式)。

@ m-ali答案是正确的,但是也要记住,如果你没有在每个块之后提交事务并执行一个检查点,日志可能会增长很多。 这是我将如何做,并采取这篇文章http://sqlperformance.com/2013/03/io-subsystem/chunk-deletes作为参考,与性能testing和图表:;

 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 

您还可以使用GO +多less次执行相同的查询。

 DELETE TOP (10000) [TARGETDATABASE].[SCHEMA].[TARGETTABLE] WHERE readTime < dateadd(MONTH,-1,GETDATE()); -- how many times you want the query to repeat GO 100 

@Francisco Goldenstein,只是一个小小的更正。 在设置variables之后必须使用COMMIT,否则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 

如果您愿意(也可以)实施分区,那么这是一种有效的技术,可以在很less的运行时间内消除大量数据。 尽pipe如此,一次性锻炼并不具有成本效益。

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循环删除小批量,如下所示:

 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 

只要几分钟,我就可以从2100万行的表中删除1900万行 。 这是我的方法。

如果你在这个表上有一个自动递增的主键 ,那么你可以使用这个主键。

  1. 获取readTime <dateadd(MONTH,-7,GETDATE())的大表的主键的最小值。 (在readTime上添加索引,如果尚未出现,则将索引随同步骤3中的表一起删除)。 让我们把它存储在一个variables'min_primary'

  2. 将所有具有主键> min_primary的行插入登台表(如果行数不大,则为内存表)。

  3. 放下大桌子。

  4. 重新创build表格。 将临时表中的所有行复制到主表中。

  5. 放下临时表。

另一种用途:

 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 

可选的;

如果事务日志已启用,请禁用事务日志。

 ALTER DATABASE dbname SET RECOVERY SIMPLE; 
Interesting Posts