J'ai deux tableaux contenant 200 millions d'enregistrements chacun. Je dois en supprimer environ 70 millions d'enregistrements, sur la base d'une valeur entière dans une colonne.
Je les supprime en morceaux de 4000, en utilisant le script suivant:
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
Le tableau A contient 6 colonnes, 5 entiers et un NVARCHAR (64). Il existe un index sur la colonne Code et clusterIndex sur le PK. TableB ne contient qu'une seule colonne, Code, c'est un PK.
Après avoir exécuté le script pendant quelques heures, il devient très très lent.
Au début, chaque itération a été exécutée en 250 ms, puis elle augmente à 2 minutes après avoir fonctionné pendant quelques heures.
La base de données est en mode de récupération simple. Il n'est utilisé par personne et fonctionne sur une machine dédiée avec 256 Go de RAM.
J'ai essayé de reconstruire les index toutes les heures, de réduire la base de données (pas le fichier parce que mon utilisateur ne peut pas) mais c'est toujours lent.
Si je commence à supprimer les enregistrements sur une autre table, il a exactement le même comportement, commençant très très rapidement, puis augmentant pour ralentir après chaque itération.
Comment puis-je restaurer les conditions initiales? Que puis-je faire pour améliorer la suppression? J'ai essayé de
Pour les suppressions importantes par lots, envisagez de spécifier une plage de clés d'index en cluster au lieu d'utiliser TOP
afin qu'une recherche d'index en cluster puisse être utilisée dans le plan. Voici un exemple.
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