我有一个大数据表。 这张表中有1000万条记录。
此查询的最佳方式是什么
Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())
答案 0 :(得分:65)
@ m-ali的回答是正确的,但请记住,如果您不在每个块之后提交事务并执行检查点,那么日志可能会增长很多。我就是这样做的,并将这篇文章http://sqlperformance.com/2013/03/io-subsystem/chunk-deletes作为参考,包括性能测试和图表:
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
答案 1 :(得分:38)
您还可以使用GO +执行相同查询的次数。
DELETE TOP (10000) [TARGETDATABASE].[SCHEMA].[TARGETTABLE]
WHERE readTime < dateadd(MONTH,-1,GETDATE());
-- how many times you want the query to repeat
GO 100
答案 2 :(得分:9)
M.Ali 的这种变化对我来说很好。它会删除一些,清除日志并重复。我正在看日志的增长,下降和重新开始。
WITH PERMISSION_SET = EXTERNAL_ACCESS
答案 3 :(得分:8)
@Francisco Goldenstein,只是一个小小的修正。设置变量后必须使用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
答案 4 :(得分:7)
如果您愿意(并且能够)实现分区,那么这是一种有效的技术,可以在几乎没有运行时开销的情况下删除大量数据。但是,一次性运动不符合成本效益。
答案 5 :(得分:4)
我能够在几分钟内从我的2100万行表中删除1900万行 。这是我的方法。
如果此表上有自动递增主键,则可以使用此主键。
获取大型表的主键的最小值,其中readTime&lt; DATEADD(月,-7,GETDATE())。 (在readTime上添加索引,如果尚未存在,则无论如何都将删除此索引以及步骤3中的表)。让我们将它存储在变量'min_primary'
插入所有具有主键&gt;的行min_primary进入临时表(如果没有行的内存表不大)。
放下大桌子。
重新创建表格。将所有行从登台表复制到主表。
删除临时表。
答案 6 :(得分:3)
您可以使用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
答案 7 :(得分:2)
另一种用途:
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;
答案 8 :(得分:1)
缩短语法
select 1
WHILE (@@ROWCOUNT > 0)
BEGIN
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
END
答案 9 :(得分:1)
如果您使用的是SQL Server 2016或更高版本,并且您的表基于要删除的列创建分区(例如Timestamp列),则可以使用此新命令按分区删除数据。
>带有(分区({|} [,... 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()
答案 10 :(得分:0)
如果我说没有循环,我可以使用GOTO
语句使用sql server删除大量记录。
例如。
IsRepeat:
DELETE TOP (10000)
FROM <TableName>
IF @@ROWCOUNT > 0
GOTO IsRepeat
像这样,您可以删除较小的删除大小的数据。
让我知道是否需要更多信息。
答案 11 :(得分:0)
如果你想删除一个有大量记录的表的记录但保留一些记录, 您可以将需要的记录保存在一个类似的表中,并截断主表,然后将保存的记录返回到主表中。