我想从1TB表中删除10GB(1%)数据。我有几篇文章要从一个巨大的表中删除大量数据,但是从巨大的表中删除较小百分比的数据并没有太多帮助。
其他细节: 尝试从访问表中删除bot数据。过滤条件是字段组合... ip in(ips列表中约有20个)和useragent类似于'%SOMETHING%'
useragent size 1024 varchar
数据可以是旧的或新的。我无法使用日期过滤器
答案 0 :(得分:1)
这是我经常使用的块中的批量删除。也许它会给你一些关于如何满足你需求的想法。我创建一个存储过程并从SQL代理作业调用proc。我通常安排它允许在执行之间进行事务日志备份,因此日志不会变得太大。如果您愿意,您可以随时以交互方式运行它。
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [DBA_Delete_YourTableName] AS
SET NOCOUNT ON;
---------------------------------------------------------
DECLARE @DaysHistoryToKeep INT
SET @DaysHistoryToKeep = 90
IF @DaysHistoryToKeep < 30
SET @DaysHistoryToKeep = 30
---------------------------------------------------------
DECLARE @continue INT
DECLARE @rowcount INT
DECLARE @loopCount INT
DECLARE @MaxLoops INT
DECLARE @TotalRows BIGINT
DECLARE @PurgeThruDate DATETIME
SET @PurgeThruDate = DATEADD(dd,(-1)*(@DaysHistoryToKeep+1), GETDATE())
SET @MaxLoops = 100
SET @continue = 1
SET @loopCount = 0
SELECT @TotalRows = (SELECT COUNT(*) FROM YourTableName (NOLOCK) WHERE CREATEDDATETIME < @PurgeThruDate)
PRINT 'Total Rows = ' + CAST(@TotalRows AS VARCHAR(20))
PRINT ''
WHILE @continue = 1
BEGIN
SET @loopCount = @loopCount + 1
PRINT 'Loop # ' + CAST(@loopCount AS VARCHAR(10))
PRINT CONVERT(VARCHAR(20), GETDATE(), 120)
BEGIN TRANSACTION
DELETE TOP (4500) YourTableName WHERE CREATEDDATETIME < @PurgeThruDate
SET @rowcount = @@rowcount
COMMIT
PRINT 'Rows Deleted: ' + CAST(@rowcount AS VARCHAR(10))
PRINT CONVERT(VARCHAR(20), GETDATE(), 120)
PRINT ''
IF @rowcount = 0 OR @loopCount >= @MaxLoops
BEGIN
SET @continue = 0
END
END
SELECT @TotalRows = (SELECT COUNT(*) FROM YourTableName (NOLOCK) WHERE CREATEDDATETIME < @PurgeThruDate)
PRINT 'Total Rows Remaining = ' + CAST(@TotalRows AS VARCHAR(20))
PRINT ''
GO
答案 1 :(得分:1)
过滤条件是... ip in(ips列表中约有20个)和useragent像'%SOMETHING%'
关于表大小,在执行删除时触摸尽可能少的行很重要。
我想象一下,在ip
列上已有索引的大小的表上。它可能有助于(或不)将列表中的20个左右的ips放在表中,而不是放在in
子句中,特别是如果它们是参数。我会查看我的查询计划。
我希望useragent like '%SOMETHING%'
通常是真的;否则这是一个昂贵的测试,因为SQL Server必须检查符合条件的ip
的每一行。如果没有,重新设计以允许查询避免like
可能是有益的。
[D]选择较小的百分比并不是真正相关的。使用选择性搜索条件(以上),绝对术语中删除事务的大小。根据定义,删除行的大小和行大小决定了事务的大小。非常大的事务可以推动机器资源。在这种情况下,将它们分解为较小的可以产生更好的性能。
我使用的最后一台服务器有0.25 TB RAM,并且很容易一次删除100万行,但不是1000万行。你的将变化;你必须尝试,观察,看到。
您愿意为机器征税多少取决于同时运行(或需要能够运行)的内容。分解一个逻辑操作的方式 - 将[条件] - 删除的所有行删除到“块”中还取决于在删除过程正在进行时,当某些块被删除而其他块仍然存在时,您希望数据库看起来像什么当下。
如果您决定将其分成块,我建议不使用固定数量的行和TOP(n)
语法,因为这是最不逻辑的解。除非您使用order by
,否则您将离开服务器以任意选择要删除的 N 行。如果您使用order by
,则需要服务器在开始删除之前对结果进行排序,可能需要在整个运行过程中多次。的Bleh!
相反,找到一些行的逻辑子集,理想情况下可以沿聚簇索引区分,它们低于机器一次要删除的可接受行数的阈值。循环遍历该集合。在您的情况下,我很想迭代ip
子句中的in
值集。而不是delete ... where ip in(...)
,你得到(大致)for each ip delete ... where ip = @ip
后一种方法的优点是您始终知道数据库的位置。如果您终止该过程或在其迭代的中途回滚,您可以检查数据库以查看仍然保留哪个ips(或者您最终使用的任何条件)。您可以避免任何类型的病态行为,因为某些查询会获得部分结果,因为您的选择标准的某些部分(仅由服务器确定)存在而其他部分已删除。在考虑你可以说的问题时,我无法删除ip 192.168.0.1,因为,而不知道哪个部分已被删除。
总而言之,我建议: