それぞれ200ミリオンのレコードを含む2つのテーブルがあります。列の整数値に基づいて、約70百万のレコードを削除する必要があります。
次のスクリプトを使用して、4000のチャンクで削除します。
DECLARE @BATCHSIZE INT, @ITERATION INT, @TOTALROWS INT, @MSG VARCHAR(500)
DECLARE @STARTTIME DATETIME, @ENDTIME DATETIME
SET NOCOUNT ON;
SET DEADLOCK_PRIORITY LOW;
SET @BATCHSIZE = 4000
SET @ITERATION = 0
SET @TOTALROWS = 0
WHILE @BATCHSIZE>0
BEGIN
SET @STARTTIME = GETDATE();
BEGIN TRANSACTION
DELETE TOP(@BATCHSIZE)
FROM [mydb].[dbo].tableA
WHERE [mydb].[dbo].tableA.Code not IN (
SELECT Code
FROM [mydb].[dbo].TableB)
SET @BATCHSIZE=@@ROWCOUNT
SET @ITERATION=@ITERATION+1
SET @TOTALROWS=@TOTALROWS+@BATCHSIZE
COMMIT TRANSACTION;
SET @ENDTIME = GETDATE();
SET @MSG = 'Iteration: ' + CAST(@ITERATION AS VARCHAR) + ' Total deletes:' + CAST(@TOTALROWS AS VARCHAR) + ' >> ' + CAST(DATEDIFF(millisecond, @STARTTIME,@ENDTIME) AS VARCHAR)
RAISERROR (@MSG, 0, 1) WITH NOWAIT
END
TableAには、6つの列、5つの整数と1つのNVARCHAR(64)が含まれています。列Codeにはインデックスがあり、PKにはclusterIndexがあります。 TableBには、Codeという1つの列しか含まれていません。これはPKです。
数時間スクリプトを実行した後、非常に遅くなりました。
最初は各反復が250ミリ秒で実行された後、数時間実行すると2分に増加します。
データベースは単純復旧モードです。誰も使用しておらず、256 GBのRAMを搭載した専用マシンで実行されています。
私は1時間ごとにインデックスを再構築しようとしましたが、データベースを縮小しました(ユーザーができないためファイルではありません)が、常に遅いです。
別のテーブルのレコードを削除し始めると、それはまったく同じ動作で、非常に速く開始され、その後、反復ごとに増加してスローダウンします。
初期状態に戻すにはどうすればよいですか?削除を改善するにはどうすればよいですか?私がしようとしました
バッチで大規模な削除を行う場合は、クラスター化インデックスシークをプランで使用できるように、TOP
を使用する代わりにクラスター化インデックスキーの範囲を指定することを検討してください。以下に例を示します。
DECLARE
@BATCHSIZE INT = 4000
, @ITERATION INT = 0
, @TOTALROWS INT = 0
, @MSG VARCHAR(500)
, @STARTTIME DATETIME
, @ENDTIME DATETIME
, @StartValue int = 0
, @EndValue int = 0
, @MaxValue int = (SELECT MAX(PK) FROM [mydb].[dbo].tableA);
SET NOCOUNT ON;
SET DEADLOCK_PRIORITY LOW;
WHILE @StartValue <= @MaxValue
BEGIN
SET @EndValue = @StartValue + @BATCHSIZE;
SET @STARTTIME = GETDATE();
DELETE FROM [mydb].[dbo].tableA
WHERE [mydb].[dbo].tableA.Code NOT IN (
SELECT Code
FROM [mydb].[dbo].TableB
)
AND [mydb].[dbo].tableA.PK >= @StartValue
AND [mydb].[dbo].tableA.PK < @EndValue;
SET @TOTALROWS=@TOTALROWS+@@ROWCOUNT;
SET @ITERATION=@ITERATION+1;
SET @ENDTIME = GETDATE();
SET @MSG = 'Iteration: ' + CAST(@ITERATION AS VARCHAR) + ' Total deletes:' + CAST(@TOTALROWS AS VARCHAR) + ' >> ' + CAST(DATEDIFF(millisecond, @STARTTIME,@ENDTIME) AS VARCHAR);
RAISERROR (@MSG, 0, 1) WITH NOWAIT;
SET @StartValue = @EndValue;
END;
GO