web-dev-qa-db-fra.com

suppression efficace de grands volumes de lignes de la table dans SQL Server

J'ai une table qui est devenue un peu hors de contrôle. Je ne suis pas un DBA en soi, mais semble me rappeler que la suppression d'un énorme volume de lignes en une seule fois peut entraîner des problèmes de journal des transactions, nuire aux performances globales du système pendant la suppression, etc.

Existe-t-il un moyen efficace de créer un travail qui supprime des enregistrements par petits lots pour gêner les autres accès/performances et éviter les problèmes avec le journal des transactions?

Ce processus peut être assez lent, c'est ce qui fait la différence

Pour un contexte supplémentaire, les critères de suppression seront basés sur quelque chose comme ... where x like '%blah%'. En outre, il existe un index cluster et 5 index non cluster.

11
JoeGeeky

Vous pouvez le diviser en morceaux - supprimer en boucle; chaque itération de suppression est sa propre transaction, puis l'effacement du journal à la fin de chaque itération de boucle. La recherche de la taille de bloc optimale nécessitera quelques tests.

Je vous suggère de lire cet article d'Aaron Bertrand, où il explique les détails et exécute des tests pour différents scénarios, pour montrer l'impact (durée, journal des transactions): http://sqlperformance.com/2013/ 03/io-subsystem/chunk-deletes

En ce qui concerne la where x like '%blah%' supprimer la condition - cela rendra la requête non sargable (ne peut pas utiliser les index pour faire une recherche d'index). Donc, même si vous avez un index pour prendre en charge la colonne x, ce sera une analyse.

Ressources pour cela:

11
Blaž Dakskobler

C'est assez simple. Voici un cadre pour vous permettre de tester.

CREATE TABLE #DelTest (ID INT IDENTITY, name NVARCHAR(128));
INSERT INTO #DelTest (name) SELECT name FROM sys.objects;
SELECT COUNT(*) TableNamesContainingSys FROM deltest WHERE name LIKE '%sys%';
go
DECLARE @HowMany INT;
DECLARE @RowsTouched INT;

SET @RowsTouched = 1;
SET @HowMany = 5;

WHILE @RowsTouched > 0
BEGIN
   DELETE TOP (@HowMany)
   FROM #DelTest 
   WHERE name LIKE '%sys%';

   SET @RowsTouched = @@ROWCOUNT;

END; 
SELECT COUNT(*) TableNamesContainingSys FROM #DelTest WHERE name LIKE '%sys%';
DROP TABLE #DelTest;

EDIT: Bien sûr, l'ouverture de recherches génériques est notoirement mauvaise pour trouver des lignes, car toute la colonne doit être recherchée. En outre, comme indiqué dans la publication d'Aaron, vous devez également gérer les journaux, soit en mode SIMPLE, soit en effectuant des sauvegardes de journaux pour empêcher les fichiers journaux de croître excessivement.

4
RLF