如果您使用的是 SQL Server 2016 或更高版本,并且您的表具有基于您要删除的列(例如 Timestamp 列)创建的分区,那么您可以使用这个新命令按分区删除数据。
TRUNCATE TABLE WITH (PARTITIONS ({ | } [ , ...n ]))
这将仅删除选定分区中的数据,并且应该是从部分表中删除数据的最有效方式,因为它不会创建事务日志,并且将与常规截断一样快,但不会全部删除从表中删除的数据。
缺点是如果您的表没有设置分区,那么您需要去老学校并使用常规方法删除数据,然后重新创建带有分区的表,以便您将来可以这样做,这就是我所做的。我将分区创建和删除添加到插入过程本身。我的表有 5 亿行,所以这是减少删除时间的唯一选择。
更多详情请参考以下链接:
https://docs.microsoft.com/en-us/sql/t-sql/statements/truncate-table-transact-sql?view=sql-server-2017
SQL server 2016 Truncate table with partitions
以下是我在重新创建包含所需数据的分区的表之前首先删除数据的操作。此查询将在指定的时间窗口内运行数天,直到数据被删除。
:connect <<ServerName>>
use <<DatabaseName>>
SET NOCOUNT ON;
DECLARE @Deleted_Rows INT;
DECLARE @loopnum INT;
DECLARE @msg varchar(100);
DECLARE @FlagDate datetime;
SET @FlagDate = getdate() - 31;
SET @Deleted_Rows = 1;
SET @loopnum = 1;
/*while (getdate() < convert(datetime,'2018-11-08 14:00:00.000',120))
BEGIN
RAISERROR( 'WAIT for START' ,0,1) WITH NOWAIT
WAITFOR DELAY '00:10:00'
END*/
RAISERROR( 'STARTING PURGE' ,0,1) WITH NOWAIT
WHILE (1=1)
BEGIN
WHILE (@Deleted_Rows > 0 AND (datepart(hh, getdate() ) >= 12 AND datepart(hh, getdate() ) <= 20)) -- (getdate() < convert(datetime,'2018-11-08 19:00:00.000',120) )
BEGIN
-- Delete some small number of rows at a time
DELETE TOP (500000) dbo.<<table_name>>
WHERE timestamp_column < convert(datetime, @FlagDate,102)
SET @Deleted_Rows = @@ROWCOUNT;
WAITFOR DELAY '00:00:01'
select @msg = 'ROWCOUNT' + convert(varchar,@Deleted_Rows);
set @loopnum = @loopnum + 1
if @loopnum > 1000
begin
begin try
DBCC SHRINKFILE (N'<<databasename>>_log' , 0, TRUNCATEONLY)
RAISERROR( @msg ,0,1) WITH NOWAIT
end try
begin catch
RAISERROR( 'DBCC SHRINK' ,0,1) WITH NOWAIT
end catch
set @loopnum = 1
end
END
WAITFOR DELAY '00:10:00'
END
select getdate()