web-dev-qa-db-fra.com

Suppression de millions d'enregistrements sur SQL Server 14.0

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

6
Giox

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
11
Dan Guzman