我有一个相当大的名为FTPLog的表,大约有3百万条记录我想添加一个删除机制来删除旧日志,但删除命令需要很长时间。我发现聚簇索引删除需要很长时间。
DECLARE @MaxFTPLogId as bigint
SELECT @MaxFTPLogId = Max(FTPLogId) FROM FTPLog WHERE LogTime <= DATEADD(day, -10 , GETDATE())
PRINT @MaxFTPLogId
DELETE FROM FTPLog WHERE FTPLogId <= @MaxFTPLogId
我想知道如何提高删除效果?
答案 0 :(得分:14)
它可能很慢,因为大型删除会生成一个大的事务日志。尝试以块的形式删除它,例如:
WHILE 1 = 1
BEGIN
DELETE TOP (256) FROM FTPLog WHERE FTPLogId <= @MaxFTPLogId
IF @@ROWCOUNT = 0
BREAK
END
这会产生较小的交易。它通过为其他过程创造喘息空间来缓解锁定问题。
您也可以查看partitioned tables。这些可能允许您通过删除整个分区来清除旧条目。
答案 1 :(得分:7)
由于它是一个日志表,因此无需进行集群化。
您不太可能在Id
上搜索。
改变你的PRIMARY KEY
,使其不合群。这将使用HEAP
上的DML
存储方法更快:
ALTER TABLE FTPLog DROP CONSTRAINT Primary_Key_Name
ALTER TABLE FTPLog ADD CONSTRAINT Primary_Key_Name PRIMARY KEY NONCLUSTERED (FTPLogId)
,只是发出:
SELECT @MaxFTPLogTime = DATEADD(day, -10 , GETDATE())
PRINT @MaxFTPLogId
DELETE FROM FTPLog WHERE LogTime <= @MaxFTPLogTime
答案 2 :(得分:1)
检查表的密度(使用命令DBCC showcontig检查密度) 扫描密度[最佳计数:实际计数] 此参数应接近100%,逻辑扫描碎片参数应接近0%,以获得最佳性能。如果不是,请重新索引和重新整理该表的索引,以提高查询执行的性能。
答案 3 :(得分:0)
我假设不仅这个表在行数方面是巨大的,而且在你尝试清理它时它实际上用于记录新条目。
Andomar的建议应该有所帮助,但是如果没有插入,我会尝试清理它。
备选:当您编写日志时,您可能并不关心事务隔离这么多。因此,我会更改写入日志条目的代码/进程的事务隔离级别,以便可能避免创建巨大的tempdb
(顺便说一句,检查tempdb在此期间是否增长很多操作)
另外,我认为聚簇索引的删除不应该比非聚簇索引的删除速度慢:你仍然 psysically 删除行。之后重建此索引可能需要一段时间。