Utilisation de SQL Server 2005.
J'effectue un énorme DELETE FROM sans clause where. C'est fondamentalement équivalent à une instruction TRUNCATE TABLE - sauf que je ne suis pas autorisé à utiliser TRUNCATE. Le problème est que le tableau est énorme - 10 millions de lignes, et il faut plus d'une heure pour terminer. Existe-t-il un moyen de le rendre plus rapide sans:
Le t-log est déjà sur un disque séparé.
Toutes les suggestions sont les bienvenues!
Ce que vous pouvez faire est de supprimer des lots comme ceci:
SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
DELETE TOP (xxx) MyTable
Où xxx est, disons, 50000
Une modification de cela, si vous souhaitez 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
Vous pouvez utiliser la clause TOP pour y parvenir facilement:
WHILE (1=1)
BEGIN
DELETE TOP(1000) FROM table
IF @@ROWCOUNT < 1 BREAK
END
Je suis d'accord avec les suggestions de regrouper vos suppressions en morceaux gérables si vous n'êtes pas en mesure d'utiliser TRUNCATE, et j'aime la suggestion drop/create pour son originalité, mais je suis curieux de savoir le commentaire suivant dans votre question:
C'est fondamentalement équivalent à une instruction TRUNCATE TABLE - sauf que je ne suis pas autorisé à utiliser TRUNCATE
Je suppose que la raison de cette restriction est liée à la sécurité qui doit être accordée pour tronquer directement une table et au fait qu'elle vous permettrait de tronquer des tables autres que celle qui vous concerne.
En supposant que c'est le cas, je me demande si la création d'une procédure stockée qui utilise TRUNCATE TABLE et utilise "EXECUTE AS" serait considérée comme une alternative viable à l'octroi des droits de sécurité nécessaires pour tronquer directement la table.
J'espère que cela vous donnera 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 de l'utilisation d'une procédure stockée de cette façon est que la procédure stockée elle-même peut être verrouillée afin que seuls des comptes spécifiques soient autorisés à l'utiliser.
Si, pour une raison quelconque, ce n'est pas une solution acceptable et que votre besoin de supprimer les données de ce tableau doit être effectué une fois par jour/heure/etc., je demande qu'un travail d'agent SQL soit créé pour tronquer le tableau. à une heure programmée chaque jour.
J'espère que cela t'aides!
Sauf tronquer .. seule la suppression par lots peut vous aider.
Vous pouvez supprimer la table et la recréer, avec toutes les contraintes et les index, bien sûr. Dans Management Studio, vous avez la possibilité de scripter une table à supprimer et à créer, il devrait donc s'agir d'une option banale. Mais cela uniquement si vous êtes autorisé à effectuer des actions DDL, ce qui, à mon avis, n'est pas vraiment une option.
Étant donné que cette question est une référence si importante, je publie ce code qui m'a vraiment aidé à comprendre la suppression avec des boucles et également la messagerie dans une boucle pour suivre les progrès.
La requête est modifiée de this question en double. Crédit à @ RLF pour la base de 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;