2017-01-23 12 views
0

でレコードを削除し、私はテーブルを持っている私は3ヶ月という古いすべてのレコードを削除したいクラスタ化または非クラスタ化インデックス

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) 
) 

(のはErrorLogをしましょう)。

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'は8バイト、 'int'はわずか4 )、おそらくクラスタ化されています。 - 選択されたレコードが連続している場合は、クラスタ化インデックスを使用する方が高速です。あなたは本当に '創造された'の中に日付と日付を持っていますか? - (日付なしの) 'Date'カラムは、4バイトだけです。 –

+0

はい、時間の部分もあります – tomassino

答えて

1

あなたが削除する最大のクラスタ化キーを知ったら、それは、このキーを使用することは間違いなく高速です。問題は、最初に日付を使用してこのキーを選択する価値があるかどうかです。適切な決定は、テーブルのサイズと削除する必要があるデータの部分によって異なります。テーブルが小さいほど、削除するレコードの数が少ないほど、より効率的なものが最初のオプション(クエリ#1)になります。ただし、削除するレコードの数が十分多い場合、日付列の非クラスタ化インデックスは無視され、SQL Serverはベーステーブルのスキャンを開始します。そのような場合には、第2の選択肢(Query#2)がより最適である可能性がある。また、通常考慮すべき他の要因もあります。

私は最近(1.5TBテーブルから約6億(2/3)古いレコードを削除して)同様の問題を解決しました。私は最後に2番目のアプローチを決めました。それにはいくつかの理由がありましたが、主なものは次のとおりです。

古いレコードが削除されている間に、新しい挿入用にテーブルを使用できるようにする必要がありました。だから、私は1つのモンスターの削除ステートメントでレコードを削除することはできませんでしたが、むしろテーブルレベルへのロックのエスカレーションを避けるために、バッチ処理された複数の小さなバッチを使用しなければなりませんでした。より小さいバッチでは、トランザクションログのサイズも合理的な制限がありました。さらに、私は毎日約1時間のメンテナンスウィンドウしか持たず、1日以内に必要なレコードをすべて削除することはできませんでした。

上記のことを念頭に置いて、私の最速の解決策は、Date列に従って削除する必要がある最大IDを選択し、次に選択したID 1のバッチまでクラスタ化インデックスの先頭から削除を開始することでした他の後に()DELETE TOP(@BatchSize)FROM ErrorLog WITH(PAGLOCK)WHERE ID < = @myMaxId)。私はPAGLOCKヒントを使用して、ロックをテーブルレベルにエスカレートせずにバッチサイズを増やしました。私は最終的に毎日いくつかのバッチを削除しました。

関連する問題