高效删除表中 90% 的数据

Cra*_*ein 5 performance sql-server delete sql-server-2008-r2

我正在研究一个删除 90% 表数据的过程,因为测试只需要 10%。

我发现的最好方法包括将表的 10% 的行存储到临时表中。

当前方法

SELECT TOP 10 PERCENT *
INTO #temp_some_table
FROM some_table (nolock)
ORDER BY some_column DESC

TRUNCATE TABLE some_table 

INSERT INTO some_table 
SELECT *
FROM #temp_some_table 

DROP TABLE #temp_some_table 
Run Code Online (Sandbox Code Playgroud)

此方法会填满 tempdb 并导致磁盘也填满。

问题

有没有更有效的方法来删除表中 90% 的数据 ex ( DELETE TOP 90 PERCENT FROM sometable)

或者

有没有办法使用批处理将 10% 的 some_table 数据插入到临时表中?像这样的东西:

DECLARE @r INT;

WHILE @r > 0
BEGIN

BEGIN TRANSACTION;

INSERT INTO [dbo].[##temp_cds_Basket]
SELECT TOP 10 PERCENT *
FROM [dbo].[cds_basket] s

SET @r = @@ROWCOUNT;
print @r 

COMMIT TRANSACTION

END
Run Code Online (Sandbox Code Playgroud)

可能的解决方案

这个怎么样?

SET NOCOUNT ON;

DECLARE @r INT;
DECLARE @TenPercentDate datetime 
with cte (some_column) as (

    select top 10 percent some_column from some_table (nolock) order by some_column desc
)
select @TenPercentDate = min(some_column)
from cte

select @TenPercentDate

 SET @r = 1;

WHILE @r > 0
BEGIN
  BEGIN TRANSACTION;

 DELETE TOP (10000) from
  some_table 
  WHERE some_column < @TenPercentDate  

  SET @r = @@ROWCOUNT;
  print @r

  COMMIT TRANSACTION;

  --CHECKPOINT;    -- if simple

END

--rollback
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 10

我在上面的评论中提到了三个不同的想法。这是对其中至少一个的详细说明(由于自我诊断的隧道视觉,您被困在其中)。

  1. 好吧,您可以事先计算出占 10% 的行数,然后在您的批次中进行比较。

我正在考虑这个,但我们实际上并不需要进行比较 - 我们可以找出我们想要保留的日期时间值是什么,并删除旧行的块,直到没有剩下的行。例如:

SET NOCOUNT ON;

DECLARE 
  @rc INT = 1, 
  @cutoff DATETIME, 
  @batchsize INT = 10000;

;WITH x(dt) AS 
(
 SELECT TOP (10) PERCENT datetime_column
  FROM dbo.mytable 
  ORDER BY datetime_column DESC
)
SELECT TOP (1) @cutoff = dt -- earliest row we want to keep
 FROM x
 ORDER BY dt;

WHILE @rc > 0
BEGIN
  DELETE TOP (@batchsize) dbo.mytable
    WHERE datetime_column < @cutoff
  SET @rc = @@ROWCOUNT;
END
Run Code Online (Sandbox Code Playgroud)

您可以查看此帖子以了解一些其他方法来增强此功能。

  1. 您可以考虑使用 drop / select into 而不是 truncate / insert,并考虑在此操作期间使用大容量日志恢复。

我认为这将是一个有效的选择,并且应该比上面的痛苦更少。

  1. 您也可以只执行一项数据移动操作:
SELECT TOP 10 PERCENT cols
  INTO dbo.newtable
  FROM dbo.oldtable
  ORDER BY datetime_column;

DROP TABLE dbo.oldtable;

EXEC sys.sp_rename N'dbo.newtable', N'dbo.oldtable', N'OBJECT';
Run Code Online (Sandbox Code Playgroud)

这个也不那么痛苦,但可以随意在其中注入一些调试,以确保在执行删除之前获得所需的数据。

请注意,在后两种情况下,可能存在约束、模式绑定视图等阻止您删除表(显然入站外键不是问题,因为您可以截断,但出站可能仍然需要待处理)。现有计划也会产生影响(删除 90% 的数据也会导致统计信息更新并使计划无效,因此实际上没有什么不同),正如@Kenneth 在下面指出的那样,您需要重新建立对新表(因此您可能希望确保您可以提前编写脚本)。