如何在没有日志的情况下删除SQL表中的大数据?
我有一个大的数据表。 这张表有1000万条logging。
这个查询的最佳方法是什么?
Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())
-
如果您正在删除该表中的所有行,最简单的select是截断表,就像
TRUNCATE TABLE LargeTable GO
截断表将简单地清空表,您不能使用WHERE子句来限制被删除的行,并且不会触发任何触发器。
-
另一方面,如果你删除了超过80-90%的数据,比如说你总共有1100万行,而你想以另一种方式删除1000万行,那么插入这100万行(logging要保留)到另一个登台表。 截断这个大表,然后插入这100万行。
-
或者,如果拥有这个大型表作为其基础表的权限/视图或其他对象不会因为删除此表而受到影响,那么可以将这些相对较less的行放到另一个表中,然后使用相同的模式创build另一个表并导入这些表回到这个ex-Large表。
-
我能想到的最后一个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万行 。 这是我的方法。
如果你在这个表上有一个自动递增的主键 ,那么你可以使用这个主键。
-
获取readTime <dateadd(MONTH,-7,GETDATE())的大表的主键的最小值。 (在readTime上添加索引,如果尚未出现,则将索引随同步骤3中的表一起删除)。 让我们把它存储在一个variables'min_primary'
-
将所有具有主键> min_primary的行插入登台表(如果行数不大,则为内存表)。
-
放下大桌子。
-
重新创build表格。 将临时表中的所有行复制到主表中。
-
放下临时表。
另一种用途:
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;