2010-08-25 24 views
6

Ho finalmente ottenuto il mio batch di inserimenti per funzionare e ora mi sono divertito con le dimensioni del batch, ma non vedo differenze nelle prestazioni tra un valore di 50 e un valore di 10000. Questo sembra molto strano per me, ma non so cosa succede dietro la scena, quindi potrebbe essere un comportamento normale.Come si imposta DataAdapter.UpdateBatchSize su un valore "ottimale"?

Sto inserendo righe 160k in una tabella e il tempo medio per i miei valori testati è 115 +/- 2 secondi. Senza batch ci vogliono 210 secondi, quindi sono abbastanza soddisfatto del miglioramento. La tabella di destinazione è:

CREATE TABLE [dbo].[p_DataIdeas](
    [wave] [int] NOT NULL, 
    [idnumber] [int] NOT NULL, 
    [ideaID] [int] NOT NULL, 
    [haveSeen] [bit] NOT NULL CONSTRAINT [DF_p_DataIdeas_haveSeen] DEFAULT ((0)), 
    CONSTRAINT [PK_p_DataIdeas] PRIMARY KEY CLUSTERED 
(
    [wave] ASC, 
    [idnumber] ASC, 
    [ideaID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON 
) ON [PRIMARY] 
) ON [PRIMARY] 

ho letto What to look for when setting UpdateBatchSize e la risposta è stata semplicemente per testare un paio di valori diversi. Posso capirlo, ma non dovrebbe essere possibile calcolare o quantomeno stimare un buon valore se si conosce la struttura della tabella, la domanda SQL e i dati che stanno per essere inseriti?

Esistono buone pratiche che qualcuno può consigliare?

risposta

5

È possibile visualizzare l'effetto del batch osservando SQL Profiler o chiamando SqlConnection.RetrieveStatistics(). Quello che dovresti vedere è che ogni lotto corrisponde a un singolo round trip nel DB.

Per quanto riguarda l'ottimizzazione della dimensione del batch, una regola empirica molto approssimativa è che le prestazioni tendono a smettere di migliorare con lotti di dimensioni superiori a circa 50 - in realtà, a volte i lotti di dimensioni maggiori possono essere eseguiti più lentamente di quelli più piccoli . Se sono troppo impegnato per testare, in genere inizio con un batch di circa 20 (a meno che non utilizzi parametri con valori di tabella, in cui i batch fino a 500 possono essere più veloci di quelli più piccoli). Tuttavia, il numero ottimale dipende da cose come la dimensione totale degli inserti (si inseriranno tutti nella RAM), la velocità con cui i dischi sono posizionati sul registro DB, se il registro si trova su un'unità/LUN di sua proprietà (grande costo perf se non lo è), ecc.

La velocità ottenibile è generalmente limitata prima dal numero di round trip, quindi dalle dimensioni della transazione, quindi dalla velocità del disco di log (in particolare se è possibile l'accesso sequenziale o se è forzato a caso a causa della concorrenza con altri file sugli stessi fusi) e infine RAM. Tuttavia, tutti i fattori sono anche correlati tra loro in una certa misura.

Il primo passo per migliorare il perf degli inserti sarebbe quello di eseguirli nelle transazioni, magari una transazione ogni lotto o due. Oltre a ciò, i parametri con valori di tabella sono probabilmente il passo successivo, utilizzando una stored procedure con INSERT INTO Table SELECT column FROM @TableArgument.

1

Anche se la modifica di UpdateBatchSize aiuterà in una certa misura, l'approccio di base dell'utilizzo di un DataAdapter per l'aggiornamento di molti record sarà lento. Questo perché, in ultima analisi, un'istruzione SQL separata (inserire, aggiornare o eliminare) verrà generata dal DataAdapter per ogni riga. UpdateBatchSize riguarda solo il numero di quelle singole istruzioni inviate in un batch TSQL quando vengono inviate a SQL Server.

Per ottenere miglioramenti molto più grandi delle prestazioni, si desidera che SQLServer inserisca/aggiorni/elimini molti record in un'unica istruzione (in genere utilizzando un JOIN di qualche tipo). I parametri con valori di tabella (come menzionato da RickNZ) sono un modo per farlo. Un'altra possibilità è l'utilizzo di SqlBulkCopy (anche se in genere è necessario utilizzare una tabella di staging per questo).

0

Assicurarsi che ci sia anche una transazione attiva migliorerà notevolmente le prestazioni (circa 30x nei miei test utilizzando MysqlDataAdapter).

Problemi correlati