2010-04-12 10 views
8

Sto testando la velocità di inserimento di più righe con una singola istruzione INSERT.Più righe con un singolo INSERT in SQLServer 2008

Ad esempio: INSERT INTO [MyTable] Valori (5, 'cane'), (6, 'gatto'), (3, 'pesce)

Questo è molto veloce fino a quando mi passa 50 righe su una singola affermazione, quindi la velocità diminuisce in modo significativo.

Inserendo 10000 righe con lotti di 50 occorrono 0,9 secondi. Inserimento di 10000 righe con lotti di 51 occorrono 5,7 secondi.

La mia domanda ha due parti:

  1. Perché c'è una tale calo le prestazioni del disco a 50?
  2. Posso fare affidamento su questo comportamento e codificare la mia applicazione per non inviare mai batch superiori a 50?

I miei test sono stati eseguiti in C++ e ADO.

Modifica: Sembra che il punto di partenza non sia 50 righe, ma 1000 colonne. Ottengo risultati simili con 50 righe di 20 colonne o 100 righe di 10 colonne.

+0

Ho la sensazione che peggiori a causa dell'analisi dell'input. – Andrey

+2

Indagine spontanea completa e totale: meno di 50 righe vengono memorizzate nella cache da SQL Server, ma gli inserti più grandi sono considerati più "importanti" e vengono immediatamente scritti sul disco? Onestamente non sono sicuro (Quindi commento piuttosto che risposta) –

risposta

0

Hai anche confrontato l'approccio "unione tutti" mostrato qui? http://blog.sqlauthority.com/2007/06/08/sql-server-insert-multiple-records-using-one-insert-statement-use-of-union-all/

Sospetto che ci sia un cache/indice interno utilizzato fino a 50 righe (è un bel numero decimale rotondo). Dopo 50 righe ricade su un algoritmo di inserimento caso generale meno efficiente in grado di gestire quantità arbitrarie di input senza utilizzare memoria eccessiva.

+0

Ho appena provato l'approccio UNION ALL. È anche piuttosto lento. Circa 7 secondi per 10000 righe. – Todd

0

il rallentamento è probabilmente l'analisi dei valori stringa: VALUES (5, 'dog'), (6, 'cat'), (3, 'fish) e non un problema INSERT.

provare qualcosa di simile, che inserirà una riga per ogni riga restituita dalla query:

INSERT INTO YourTable1 
    (col1, col2) 
    SELECT 
     Value1, Value2 
     FROM YourTable2 
     WHERE ...--rows will be more than 50 

e vedere cosa succede

0

Se si utilizza SQL 2008, quindi è possibile utilizzare il valore tavolo parametri e basta fare una singola istruzione di inserimento.

personalmente, non ho mai visto il rallentamento a 50 record di inserimenti anche con lotti regolari. Indipendentemente da ciò, siamo passati ai parametri del valore di tabella che ha avuto un significativo aumento di velocità per noi.

+0

Ho provato questo, e come un novizio SQL, non sono certo di farlo nel modo più ottimale. Tuttavia i miei test mostrano da 6 secondi a 30 secondi per 10000 righe, a seconda delle dimensioni del batch. Nulla di vicino alle istruzioni INSERT multi riga. – Todd

+0

Questo è molto strano. Stai assegnando tutti i campi nella tabella o alcuni sono assegnati attraverso i valori predefiniti della colonna? Se più tardi, questi possono essere costosi (come la funzione getdate()) ... – NotMe

+0

Ho seguito l'esempio qui: http://msdn.microsoft.com/en-us/library/bb510489%28SQL.100%29. aspx Ma invece di inserirmi nella tabella temporanea da un'altra tabella, inserisco i valori usando un inserto multi riga. Specifico tutti i valori, nessun valore di default. – Todd

0

Pensieri casuali:

  • è completamente coerente quando viene eseguito più volte?
  • stai verificando la presenza di duplicati nelle prime 10 righe per il secondo inserto da 10 k?
  • hai provato prima la dimensione del batch di 51?
  • hai svuotato la tabella tra i test?
+0

Sì, è molto coerente. E svuoto il tavolo tra ogni test. – Todd

+0

@Todd: interessante. Buona domanda. E non ho altre idee però :-) – gbn

2

Potrebbe anche essere correlato alla dimensione della riga. La tabella che usi come esempio sembra avere solo 2 colonne. Cosa succede se ha 25 colonne? Le prestazioni diminuiscono anche a 50 righe?

+0

Interessante. La tabella sopra era solo un esempio, la mia tabella attuale contiene 20 colonne. Ho ridotto a 10 e ho provato di nuovo. Ora ottengo il taglio a 100. I batch di 100 impiegano circa 0,6 secondi. I lotti di 101 impiegano circa 3,25 secondi. Sembra che il limite non sia 50 righe, ma 1000 singoli campi aggiornati? – Todd

+0

Sembra che il taglio sia più simile ai dati totali in memoria. Se una tabella è piccola, allora forse puoi inserire 100 righe in un "blocco", qualunque sia un blocco. Ma tabelle di grandi dimensioni, con molte colonne o con poche colonne di grandi dimensioni (ad es. VARCHAR (1200)) limiterebbero il numero di righe che potreste inserire in un blocco. – MJB

0

Per inserti ad alto volume e alta frequenza, considerare l'utilizzo di Bulk Inserts per caricare i dati. Non è la cosa più semplice da implementare nel mondo e porta con sé una nuova serie di sfide, ma può essere molto più veloce di un INSERT.

Problemi correlati