在具有聚簇索引的表中,DELETE命令太慢

时间:2009-05-27 08:39:33

标签: sql sql-server-2005

我有一个相当大的名为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

我想知道如何提高删除效果?

4 个答案:

答案 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 删除行。之后重建此索引可能需要一段时间。