按聚簇索引或非聚簇索引删除记录

时间:2017-01-23 17:17:48

标签: sql sql-server

我有一张桌子(让我们说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

1 个答案:

答案 0 :(得分:1)

一旦知道了要删除的最大群集密钥,那么使用此密钥肯定会更快。问题是,是否值得首先使用日期选择此密钥。正确的决定取决于表的大小以及您需要删除的数据部分。表越小,删除的记录数越小,效率越高,第一个选项(查询#1)。但是,如果要删除的记录数足够大,则将忽略Date列上的非聚集索引,SQL Server将开始扫描基表。在这种情况下,第二个选项(查询#2)可能更优。而且通常还有其他因素需要考虑。

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

在删除旧记录时,该表必须可用于新插入。所以,我无法删除一个monstrous delete语句中的记录,而是我必须使用几个较小的批处理,以避免锁升级到表级。较小的批次也使事务日志大小保持在合理的限度内。此外,我每天只有大约一个小时的维护时间,并且无法在一天内删除所有必需的记录。

考虑到上述情况,对我来说最快的解决方案是根据Date列选择我需要删除的最大ID,然后从聚簇索引的开头到开始删除一个批处理后的一个ID另一个( DELETE TOP(@BatchSize)FROM ErrorLog WITH(PAGLOCK)WHERE ID&lt; = @myMaxId )。我使用PAGLOCK提示来增加批量大小而不将锁升级到表级。我最后每天都删除了几批。