2010-01-26 18 views
8

Supponiamo di disporre di una tabella con record 10000000. Qual è la differenza tra questa soluzione?Elimina una grande quantità di dati nel server sql

  1. Elimina dati come:

    DELETE FROM MyTable 
    
  2. eliminare tutti i dati con una fila di applicazione per riga:

    DELETE FROM MyTable WHERE ID = @SelectedID 
    

è la prima soluzione ha migliori prestazioni? qual è l'impatto sul log e sulle prestazioni?

risposta

14

Se si dispone di molti record nella tabella e si desidera eliminarli tutti, è necessario considerare truncate <table> anziché delete from <table>. Sarà molto più veloce, ma tieni presente che non può attivare un trigger.

Vedere per maggiori dettagli (questo server caso sql 2000): http://msdn.microsoft.com/en-us/library/aa260621%28SQL.80%29.aspx

eliminazione della tabella all'interno dell'applicazione riga per riga finirà nel lungo periodo di tempo lungo, come il vostro DBMS non può ottimizzare il nulla, come non sa in anticipo, che cancellerai tutto.

+4

È possibile eseguire il rollback di un troncato se si è ancora all'interno dell'ambito della transazione eseguito, contrariamente a quanto si crede sia transazionale - lo IAM deallocato è non cancellato fino al commit in modo che possa essere ripristinato reintegrando lo IAM. – Andrew

+0

Basta leggerlo e hai ragione, in SQL Server puoi eseguire il rollback di un troncato. Avevo oracle in mente dove non è possibile (secondo la documentazione). –

+0

Non riesco a utilizzare TRUNCATE perché MyTable ha una chiave esterna anch'io ho bisogno della clausola WHERE per i dati del filtro –

3

Il primo ha prestazioni decisamente migliori.

Quando si specifica DELETE [MyTable], verrà semplicemente cancellato tutto senza eseguire controlli per ID. Il secondo sprecherà tempo e operazioni sul disco per localizzare un rispettivo record ogni volta prima di eliminarlo.

Inoltre, peggiora perché ogni volta che un record scompare dal centro del tavolo, il motore potrebbe voler condensare i dati su disco, perdendo così tempo e lavoro di nuovo.

Forse un'idea migliore sarebbe quella di eliminare i dati in base alle colonne dell'indice cluster in ordine decrescente. Quindi la tabella sarà fondamentalmente troncata dalla fine ad ogni operazione di cancellazione.

+0

prego di dirmi perché. –

+0

tu dici che: "Forse un'idea migliore sarebbe quella di eliminare i dati in base alle colonne dell'indice cluster in ordine decrescente, quindi la tabella verrà fondamentalmente troncata dalla fine ad ogni operazione di cancellazione." puoi descrivere di più? –

+0

Il motore di database assegna fisicamente i dati sul disco nell'ordine del disco in cluster. Se si eliminassero i record con i valori di indice più alti, ciò porterebbe sostanzialmente a tagliare la coda del file, senza condensare i dati che potrebbero verificarsi se si rimuovesse qualcosa nel mezzo del file. Questo è particolarmente importante quando aggiungi dei record per provare ad averli aggiunti alla fine del file. Posso immaginare che rimuovere i record dalla fine migliorerebbe anche le prestazioni. –

3

L'opzione 1 creerà una transazione molto grande e avrà un grande impatto sul log/prestazioni, oltre a blocchi di escalation in modo che la tabella non sia disponibile. L'opzione 2 sarà più lenta, anche se genererà meno impatto sul log (supponendo bulk/modalità completa)

Se si desidera eliminare tutti i dati, Tronca tabella MyTable sarebbe più veloce di entrambi, anche se ha nessuna possibilità di filtrare le righe, esegue una modifica dei metadati sul retro e in pratica rilascia lo IAM sul pavimento per la tabella in questione.

+0

Non riesco a utilizzare TRUNCATE perché MyTable ha una chiave esterna anch'io ho bisogno della clausola WHERE per i dati del filtro –

0

Il primo sarà eliminare tutti i dati della tabella e avrà prestazioni migliori che il secondo che cancellerà solo i dati da un tasto specifico.

Ora, se è necessario eliminare tutti i dati dalla tabella e non si basano sull'utilizzo di rollback pensare all'uso di un truncate table

21

Se è necessario limitare a ciò che le righe è necessario eliminare e non fare una completa eliminazione, o non è possibile utilizzare TRUNCATE tABLE (ad esempio, la tabella è referenziato da un vincolo FK, o incluso in una vista indicizzata), allora si può fare la cancellazione in blocchi:

DECLARE @RowsDeleted INTEGER 
SET @RowsDeleted = 1 

WHILE (@RowsDeleted > 0) 
    BEGIN 
     -- delete 10,000 rows a time 
     DELETE TOP (10000) FROM MyTable [WHERE .....] -- WHERE is optional 
     SET @RowsDeleted = @@ROWCOUNT 
    END 

in generale, TRUNCATE è il modo migliore e lo userei se possibile. Ma non può essere utilizzato in tutti gli scenari. Inoltre, nota che TRUNCATE ripristinerà il valore IDENTITY per la tabella se ce n'è uno.

Se si utilizza SQL 2000 o versioni precedenti, la condizione TOP non è disponibile, quindi è possibile utilizzare SET ROWCOUNT.

DECLARE @RowsDeleted INTEGER 
SET @RowsDeleted = 1 
SET ROWCOUNT 10000 -- delete 10,000 rows a time 

WHILE (@RowsDeleted > 0) 
    BEGIN 
     DELETE FROM MyTable [WHERE .....] -- WHERE is optional 
     SET @RowsDeleted = @@ROWCOUNT 
    END 
+2

Si consiglia di evitare l'utilizzo di SET ROWCOUNT a favore di SELECT/INSERT/UPDATE/DELETE TOP (N) ... Il motivo? Dai un'occhiata qui: http://msdn.microsoft.com/en-us/library/ms143729.aspx e qui: https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=282528 –

+0

Buon punto (supponendo SQL 2005 o versioni successive) che è probabilmente una scommessa sicura. Aggiornato la mia risposta – AdaTheDev

0

Trovato questo post on Microsoft TechNet.

Fondamentalmente, si raccomanda:

  1. Utilizzando SELECT INTO, copiare i dati che si desidera conservare per una tabella intermedia;
  2. Tronca la tabella di origine;
  3. Copia indietro con INSERT INTO dalla tabella intermedia, i dati alla tabella di origine;

..

BEGIN TRANSACTION 

SELECT * 
    INTO dbo.bigtable_intermediate 
    FROM dbo.bigtable 
    WHERE Id % 2 = 0; 

    TRUNCATE TABLE dbo.bigtable; 

    SET IDENTITY_INSERT dbo.bigTable ON; 
    INSERT INTO dbo.bigtable WITH (TABLOCK) (Id, c1, c2, c3) 
    SELECT Id, c1, c2, c3 FROM dbo.bigtable_intermediate ORDER BY Id; 
    SET IDENTITY_INSERT dbo.bigtable OFF; 
ROLLBACK TRANSACTION 
Problemi correlati