2013-03-21 11 views
9

Ho un tavolo molto grande, quindi mi sto usando il seguente per eliminare le voci più vecchie:SQL Server eliminare utilizzando ciclo WHILE non funziona

WHILE (@@ROWCOUNT > 0) 
BEGIN 
    DELETE TOP (5000) FROM myTable 
    WHERE date < 20130103 
END 

ho eseguito un paio di volte con date diverse. A volte funziona bene (dura circa 20 minuti), ma altre volte la query termina immediatamente e nulla è stato cancellato. Quando ciò accade, eseguo semplicemente una semplice istruzione SELECT da quella tabella, quindi riprovo l'istruzione WHILE sopra riportata e quindi funziona! Qualcuno sa perché questo è? Ho bisogno di automatizzare questa query per funzionare regolarmente per controllare le dimensioni della tabella, ma voglio assicurarmi che in realtà venga eliminata correttamente quando viene eseguita. Grazie.

+6

Non dovrebbe essere la data scritto come ' '2013-01-03'' piuttosto che come un numero? –

+0

Divertente che ogni risposta lo abbia totalmente perso. –

+4

Si noti inoltre che il solo ciclo non riduce necessariamente l'impatto sul log o sulla concorrenza a seconda che si tratti di una singola transazione.Vorrei smettere di usare @@ ROWCOUNT per il controllo, aggiungere transazioni all'interno del ciclo e impostare una variabile = @@ ROWCOUNT. Vedere http://www.sqlperformance.com/2013/03/io-subsystem/chunk-deletes –

risposta

8

Presumibilmente, il motivo è perché @@ROWCOUNT è inizializzato a un valore pari a 0.

Si potrebbe eseguire la query prima di impostarlo:

select count(*) from myTable where date < 20130103 

Questo dovrebbe aggiungere un po 'di tempo per la vostra query, ma vedresti il ​​numero di righe eliminate.

Si potrebbe anche fare qualcosa di simile:

select top 1  * from myTable 

che sarebbe molto più veloce.

+8

Si potrebbe anche solo "SELEZIONARE 1;" prima del ciclo. –

27

Cosa stai facendo prima di questo blocco di codice? @@ROWCOUNT verrà impostato su qualunque istruzione eseguita .. se si esegue un altro comando in anticipo, potrebbe essere 0.

Invece, si potrebbe forzare il conteggio iniziale di essere 1:

DECLARE @Rows INT 
SET @Rows = 1 

WHILE (@Rows > 0) 
BEGIN 
    DELETE TOP (5000) FROM myTable 
    WHERE date < 20130103 

    SET @Rows = @@ROWCOUNT 
END 
4

E 'perché a volte @@ROWCOUNT è pari a zero per cominciare - in modo che il ciclo while mai eseguito, perché controlla la condizione prima ogni esecuzione , incluso il primo.

Ecco un fatto in casa do-while ciclo, dal momento che SQL Server non dispone di uno costruito nel

loop: 
    DELETE TOP (5000) FROM myTable 
    WHERE date < 20130103 
if @@ROWCOUNT > 0 goto loop 
+1

SQL Server non ha un ['WHILE'loop] (http://msdn.microsoft.com/en-us/library/ms178642 (v = sql.100) .aspx)? –

+5

@AaronBertrand sta parlando di un ciclo "do-while". Come in: 'DO BEGIN END WHILE ' (esegue sempre "" una volta prima di verificare la condizione). CHE non esiste in SQL Server. – EvilBob22

1

Si potrebbe anche scrivere la vostra richiesta in questo modo:.

SET ROWCOUNT 5000; -- set batch size 
WHILE EXISTS (SELECT 1 FROM myTable WHERE date < '2013-01-03') 
BEGIN 
    DELETE FROM myTable 
    WHERE date < '2013-01-03' 
END; 
SET ROWCOUNT 0; -- set batch size back to "no limit" 

In entrambi i casi, è necessario formattarla le tue stringhe di data correttamente.

Accertati solo che i criteri di eliminazione e l'istruzione nella clausola exist siano identici o che potresti incontrare un ciclo infinito.

+3

Tenere presente che dopo SQL 2012: "L'utilizzo di SET ROWCOUNT non influirà sulle istruzioni DELETE, INSERT e UPDATE in una futura versione di SQL Server. Evita di utilizzare SET ROWCOUNT con le istruzioni DELETE, INSERT e UPDATE nel nuovo lavoro di sviluppo e pianifica di modificare le applicazioni attualmente in uso. Per un comportamento simile, utilizzare la sintassi TOP. " –

0

In sostanza,

SELECT 0 -- rowcount is 1 
WHILE (@@ROWCOUNT > 0) 
BEGIN 
    DELETE TOP (5000) FROM myTable 
    WHERE date < 20130103 
END 

O

SET ROWCOUNT 5000 -- set row count to 5000 
SELECT 0 -- rowcount is 1 
WHILE (@@ROWCOUNT > 0) 
BEGIN 
    DELETE FROM myTable 
    WHERE date < 20130103 
END 
SET ROWCOUNT 0 -- set rowcount to unlimited