Metodi di accelerare un enorme DELETE FROM con clausole

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

  •  16-10-2019
  •  | 
  •  

Domanda

Utilizzo di SQL Server 2005.

Io sono l'esecuzione di un enorme DELETE FROM senza dove clausole. E 'fondamentalmente equivalente a una dichiarazione TRUNCATE TABLE - tranne che non mi è permesso di utilizzare TRUNCATE. Il problema è il tavolo è enorme - 10 milioni di righe, e ci vuole più di un'ora per completare. C'è un modo di rendere più veloce senza:

  • Uso Tronca
  • disattivare o eliminare gli indici?

La t-log è già su un disco separato.

Qualche suggerimento benvenuto!

È stato utile?

Soluzione

Che cosa si può fare è eliminazioni in batch come questo:

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

dove xxx è, diciamo, 50000

Una modifica di questo, se si desidera rimuovere una percentuale molto alta di righe ...

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

Altri suggerimenti

È possibile utilizzare la clausola TOP per ottenere questo fatto facilmente:

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

Sono d'accordo con i suggerimenti per lotto tuoi Elimina in blocchi gestibili se non si è in grado di utilizzare TRUNCATE, e mi piace il drop / creare il suggerimento per la sua originalità, ma io sono curioso di sapere il seguente commento nella tua domanda:

E 'fondamentalmente equivalente a una dichiarazione TRUNCATE TABLE - tranne che non sono autorizzato a utilizzare TRUNCATE

sto cercando di indovinare il motivo di questa limitazione ha a che fare con la sicurezza che deve essere concesso per troncare direttamente un tavolo e il fatto che permetterebbe di troncare le tabelle diversi da quello siete interessati con.

Supponendo che è il caso, mi chiedo se avendo una stored procedure creato che usi TRUNCATE TABLE e usi "eseguire come" potrebbe essere considerato una valida alternativa a dare diritti di sicurezza necessari per troncare direttamente al tavolo.

Speriamo che questo darebbe la velocità necessaria rispondendo anche alle preoccupazioni di sicurezza che l'azienda può avere con l'aggiunta di tuo account per il ruolo db_ddladmin.

Un altro vantaggio di usare una procedura immagazzinata questo modo è che la stored procedura stessa potrebbe essere bloccato in modo che solo account specifico (s) sono autorizzati ad utilizzarla.

Se per qualche motivo questo non è una soluzione accettabile e il vostro bisogno di avere i dati in questa tabella rimosso è qualcosa che deve essere fatto una volta al giorno / ora / etc, vorrei chiedere che un processo di SQL Agent è stato creato per troncare la tabella in un momento in programma ogni giorno.

Spero che questo aiuti!

Ad eccezione troncare .. eliminare solo in lotti può aiutare.

Si potrebbe eliminare la tabella e ricrearla, con tutti i vincoli e gli indici, fuori rotta. In Management Studio si ha la possibilità di script di un tavolo di cadere e creare, quindi dovrebbe essere una scelta banale. Ma questo solo se si è permesso di fare azioni DDL, che vedo che non è davvero un'opzione.

Dal momento che questa domanda è un punto di riferimento così importante sto postando questo codice che realmente mi ha aiutato a capire la cancellazione con i loop e anche di messaggistica all'interno di un ciclo per monitorare i progressi.

La query viene modificata da questa domanda duplicato . Credito al @RLF per la base di query.

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a dba.stackexchange
scroll top