2017-01-23 136 views
0

我有一个表中删除记录(假设ErrorLog通过群集或非聚集索引

enter image description here

CREATE TABLE [dbo].[ErrorLog] 
(
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [Created] [datetime] NOT NULL, 
    [Message] [varchar](max) NOT NULL, 

    CONSTRAINT [PK_ErrorLog] 
     PRIMARY KEY CLUSTERED ([Id] ASC) 
) 

我想删除是老年人有3个月向所有记录。

我在Created列(升序)上有一个非聚集索引。

我不确定哪一个更好(似乎需要相同的时间)。

查询#1

DELETE FROM ErrorLog 
WHERE Created <= DATEADD(month, - 3, GETDATE()) 

查询#2

DECLARE @id INT 

SELECT @id = max(l.Id) 
FROM ErrorLog l 
WHERE l.Created <= DATEADD(month, - 3, GETDATE()) 

DELETE FROM ErrorLog 
WHERE Id <= @id 
+0

第一种方法是非常好的 –

+1

最后一种方法应该更快,因为'id'已经具有只有一半宽度的索引,...('DateTime's是8个字节,'int's只有4个),并且可能是聚类的。 - 如果选择的记录是连续的,则使用聚簇索引会更快。 ''创造''你真的有时间和日期吗? - 导致“日期”列(没有时间),也只有4个字节。 –

+0

是的,也有一个时间部分 – tomassino

回答

1

一旦你知道最大聚集键要删除那绝对更快地使用这个键。问题是,是否值得使用日期首先选择这个键。正确的决定取决于表的大小和你需要删除的数据部分。表格越小,删除的记录数越小,第一个选项(Query#1)应该更有效率。但是,如果要删除的记录数足够大,则“日期”列上的非聚集索引将被忽略,SQL Server将开始扫描基表。在这种情况下,第二个选项(查询#2)可能更优化。通常还有其他因素需要考虑。

我最近解决了类似问题(从1.5TB表中删除了约6亿(2/3)个旧记录),并且最终决定采用第二种方法。有几个原因,但主要如下。

表必须可用于新插入,而旧记录正在被删除。所以,我无法删除一个怪异的删除语句中的记录,但我不得不使用几个较小的批处理,以避免锁升级到表级别。较小的批次也使交易日志大小保持在合理的范围内。此外,我每天只有大约一个小时的维护时间,并且不可能在一天内删除所有需要的记录。

考虑到上面提到的,最快的解决方案是选择我需要根据日期列删除的最大ID,然后从聚集索引开始删除,直到选定的Id一批之后(DELETE TOP(@BatchSize)FROM ErrorLog WITH(PAGLOCK)WHERE ID < = @myMaxId)。我使用PAGLOCK提示来增加批量大小,而不会将锁升级到表级别。我最终每天都删除了几批。