2017-01-23 201 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提示來增加批量大小,而不會將鎖升級到表級別。我最終每天都刪除了幾批。