Les méthodes d'accélérer un énorme SUPPRIMER FROM sans clauses

dba.stackexchange https://dba.stackexchange.com/questions/1750

  •  16-10-2019
  •  | 
  •  

Question

Utilisation de SQL Server 2005.

J'effectue un énorme SUPPRIMER DE sans clauses où. Il est essentiellement équivalent à une instruction TRUNCATE TABLE - sauf que je ne suis pas autorisé à utiliser TRUNCATE. Le problème est la table est énorme - 10 millions de lignes, et il faut plus d'une heure. Est-il possible de le rendre plus rapide sans:

  • Utilisation Tronquer
  • Désactivation ou suppression d'index?

Le t-journal est déjà sur un disque séparé.

Toutes les suggestions sont les bienvenus!

Était-ce utile?

La solution

Qu'est-ce que vous pouvez faire est de suppressions lot comme celui-ci:

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable

Où xxx est, par exemple, 50000

Une modification de ce fait, si vous voulez supprimer un pourcentage très élevé de lignes ...

SELECT col1, col2, ... INTO #Holdingtable
           FROM MyTable WHERE ..some condition..

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable WHERE ...

INSERT MyTable (col1, col2, ...)
           SELECT col1, col2, ... FROM #Holdingtable

Autres conseils

Vous pouvez utiliser la clause TOP pour obtenir ce fait facilement:

WHILE (1=1)
BEGIN
    DELETE TOP(1000) FROM table
    IF @@ROWCOUNT < 1 BREAK
END

Je suis d'accord avec les suggestions de vos lots en morceaux gérables suppressions si vous n'êtes pas en mesure d'utiliser TRUNCATE, et je comme la goutte / suggestion pour créer son originalité, mais je suis curieux de savoir le commentaire suivant dans votre question:

  

Il est essentiellement équivalent à une instruction TRUNCATE TABLE - sauf que je ne suis pas autorisé à utiliser TRUNCATE

Je devine la raison de cette restriction a à voir avec la sécurité qui doit être accordée à tronquer directement une table et le fait qu'il vous permettra de tronquer tables autres que celui que vous êtes concernés par.

En supposant tel est le cas, je me demande si avoir une procédure stockée créée qui utilise la table TRUNCATE et utilisations « EXECUTE AS » serait considérée comme une alternative viable à l'octroi de droits de sécurité nécessaires pour tronquer directement la table.

Si tout va bien, cela vous donne la vitesse dont vous avez besoin tout en répondant aux problèmes de sécurité que votre entreprise peut avoir avec l'ajout de votre compte au rôle db_ddladmin.

Un autre avantage d'utiliser une procédure stockée ainsi que la procédure stockée lui-même pourrait être verrouillé de sorte que seul compte spécifique (s) sont autorisés à l'utiliser.

Si pour une raison quelconque ce n'est pas une solution acceptable et votre besoin d'avoir les données dans ce tableau supprimé est quelque chose qui doit être fait une fois par jour / heure / etc, je demande qu'un travail de l'Agent SQL a été créé pour tronquer la table à une heure programmée chaque jour.

Hope this helps!

Sauf troncature .. supprimer uniquement par lots peuvent vous aider.

Vous pourriez laisser tomber la table et la recréer, avec toutes les contraintes et les index, hors cours. Dans Management Studio vous avez la possibilité de scripter une table pour déposer et de créer, il devrait donc être une option triviale. Mais cela seulement si vous êtes autorisé à faire des actions ddl que je vois ce n'est pas vraiment une option.

Étant donné que cette question est une telle référence importante que je poste ce code qui m'a vraiment aidé à comprendre la suppression de boucles et de messagerie également dans une boucle pour suivre les progrès.

La requête est modifiée de cette double question. Crédit @RLF pour la base de la requête.

CREATE TABLE #DelTest (ID INT IDENTITY, name NVARCHAR(128)); -- Build the test table
INSERT INTO #DelTest (name) SELECT name FROM sys.objects;  -- fill from system DB
SELECT COUNT(*) TableNamesContainingSys FROM #deltest WHERE name LIKE '%sys%'; -- check rowcount
go
DECLARE @HowMany INT;
DECLARE @RowsTouched INT;
DECLARE @TotalRowCount INT;
DECLARE @msg VARCHAR(100);
DECLARE @starttime DATETIME 
DECLARE @currenttime DATETIME 

SET @RowsTouched = 1; -- Needs to be >0 for loop to start
SET @TotalRowCount=0  -- Total rows deleted so far is 0
SET @HowMany = 5;     -- Variable to choose how many rows to delete per loop
SET @starttime=GETDATE()

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

   SET @RowsTouched = @@ROWCOUNT; -- Rows deleted this loop
   SET @TotalRowCount = @TotalRowCount+@RowsTouched; -- Increment Total rows deleted count
   SET @currenttime = GETDATE();
   SELECT @msg='Deleted ' + CONVERT(VARCHAR(9),@TotalRowCount) + ' Records. Runtime so far is '+CONVERT(VARCHAR(30),DATEDIFF(MILLISECOND,@starttime,@currenttime))+' milliseconds.'
   RAISERROR(@msg, 0, 1) WITH NOWAIT;  -- Print message after every loop. Can't use the PRINT function as SQL buffers output in loops.  

END; 
SELECT COUNT(*) TableNamesContainingSys FROM #DelTest WHERE name LIKE '%sys%'; -- Check row count after loop finish
DROP TABLE #DelTest;
Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top