【发布时间】:2015-12-01 03:12:01
【问题描述】:
我有一张表(比如tableB),其中有大约 4000 万行(一直在增加)。归档目前由DELETE .. OUTPUT .. INTO .. FROM .. 方式完成。归档 1000 行需要 3~5 秒
最初。但是随着越来越多的行被删除,它需要更多的时间。例如,删除 10M 行后,现在需要 35~40 秒
删除 1000 行。
这是什么原因造成的? 我该如何改善这种情况(我需要归档至少 30M 行)? 如果分区是唯一的方法,我怎样才能以最少的停机时间做到这一点?
其他信息:
-
tableB有 2 个外键列(tableAId、tableCId) - 正在根据
tableA中的日期时间字段执行存档(inner-join正在DELETE语句中使用) - 查询计划显示内部连接的成本为 81%
- 如果我对
tableA使用查询提示with (index=ix_time),则计划显示tableB的外键列上的索引的索引查找成本为100% -
tableA和tableB都具有自动递增的bigint作为主键。 -
tableB有 4 个索引 -
tableA有 5 个索引 -
tableA有 30M+ 行。 - 每天都在重建/重组/更新指数/统计数据
- SQL Server 2008R2
- Windows Server 2008R2,16 核,32G RAM
- 我是一个偶然的dba atm
查询计划摘录:
脚本:
DECLARE @older_than datetime2(0) = '2015-10-01';
DECLARE @i int = 1;
DECLARE @j int = 0;
DECLARE @imax int = 1000;
DECLARE @jmax int = 50;
DECLARE @total int = 0;
DECLARE @t1 DATETIME2(3);
DECLARE @t2 DATETIME2(3);
DECLARE @timetook int;
WHILE @i > 0 AND @j < @jmax
BEGIN
SET @t1 = GETDATE();
DELETE TOP (@imax) ss
OUTPUT deleted.[Id]
,deleted.[columnA]
,deleted.[columnB]
INTO [MyArchive_Data].dbo.tableB([Id]
,columnA
,columnB)
FROM [MyLive_Data].dbo.tableB ss
INNER JOIN [MyLive_Data].dbo.tableA s ON s.Id = ss.tableAID
WHERE s.Time < @older_than;
SET @i = @@rowcount;
SET @j = @j + 1;
SET @total = @total + @i;
SET @t2 = GETDATE();
SET @timetook = datediff(second,@t1,@t2);
RAISERROR('LOOP %d COMPLETE [%d rows][%d sec]',10,1,@j, @total, @timetook) with nowait;
WAITFOR DELAY '00:00:03';
END
更新
如果我排除循环构造(WHILE @i > 0 AND @j < @jmax)并仅单独运行 DELETE 语句,似乎需要 10~12 秒。我观察了查询计划。那些是不同的。循环结构打开时,它使用index-seek,但没有它,则使用index-scan。为什么?
【问题讨论】:
-
你能发表你的
DELETE声明吗? -
在执行删除操作时尝试禁用索引,因为索引会降低删除性能,因为 SQL 服务器必须在每次删除后更新索引。
-
@Felix Pamittan:已发布脚本
-
您使用的是
TOP,而没有ORDER BY。这是故意的吗? -
除了您的时间标准之外,考虑按 ID 范围删除,而不是使用 TOP 删除。我希望这会提供搜索而不是扫描。
标签: sql-server database database-administration