Per quanto posso dire, è possibile ottimizzare un inserto di massa in un modo molto simile che si ottimizzerebbe un inserto regolare. In genere, un piano di query per un semplice inserto non è molto informativo, quindi non preoccuparti di non avere il piano. Esaminerò alcuni modi per ottimizzare un inserto, ma la maggior parte di essi probabilmente non si applica all'inserto specificato nella domanda. Tuttavia, potrebbero essere utili se in futuro è necessario caricare grandi quantità di dati.
1. Inserire i dati nell'ordine delle chiavi del clustering
SQL Server ordinerà spesso i dati prima di inserirli in una tabella con un indice cluster. Per alcune tabelle e applicazioni è possibile migliorare le prestazioni ordinando i dati nel file flat e facendo sapere a SQL Server che i dati sono ordinati tramite l' ORDER
argomento di BULK INSERT
:
ORDINE ({colonna [ASC | DESC]} [, ... n])
Specifica come vengono ordinati i dati nel file di dati. Le prestazioni di importazione bulk vengono migliorate se i dati importati vengono ordinati in base all'indice cluster sulla tabella, se presente.
Dato che stai usando una IDENTITY
colonna come chiave cluster non devi preoccuparti di questo.
2. Utilizzare TABLOCK
se possibile
Se hai la certezza di avere solo una sessione per inserire dati nella tabella, puoi specificare l' TABLOCK
argomento per BULK INSERT
. Ciò può ridurre la contesa tra i blocchi e può portare a una registrazione minima in alcuni scenari. Tuttavia, si sta inserendo in una tabella con un indice cluster che già contiene dati, quindi non si otterrà una registrazione minima senza il flag di traccia 610 che verrà menzionato più avanti in questa risposta.
Se TABLOCK
non è possibile, poiché non è possibile modificare il codice , non tutte le speranze vanno perse. Prendi in considerazione l'utilizzo di sp_table_option
:
EXEC [sys].[sp_tableoption]
@TableNamePattern = N'dbo.BulkLoadTable' ,
@OptionName = 'table lock on bulk load' ,
@OptionValue = 'ON'
Un'altra opzione è abilitare il flag di traccia 715 .
3. Utilizzare una dimensione del lotto appropriata
A volte sarai in grado di ottimizzare gli inserti modificando la dimensione del batch.
ROWS_PER_BATCH = rows_per_batch
Indica il numero approssimativo di righe di dati nel file di dati.
Per impostazione predefinita, tutti i dati nel file di dati vengono inviati al server come un'unica transazione e il numero di righe nel batch è sconosciuto a Query Optimizer. Se si specifica ROWS_PER_BATCH (con un valore> 0), il server utilizza questo valore per ottimizzare l'operazione di importazione in blocco. Il valore specificato per ROWS_PER_BATCH dovrebbe approssimativamente essere uguale al numero effettivo di righe. Per informazioni sulle considerazioni sulle prestazioni, consultare "Note" più avanti in questo argomento.
Ecco la citazione di seguito nell'articolo:
Se il numero di pagine da scaricare in un singolo batch supera una soglia interna, potrebbe verificarsi una scansione completa del pool di buffer per identificare le pagine da scaricare quando si esegue il commit del batch. Questa scansione completa può compromettere le prestazioni di importazione di massa. Un probabile caso di superamento della soglia interna si verifica quando un pool buffer di grandi dimensioni viene combinato con un sottosistema I / O lento. Per evitare overflow del buffer su macchine di grandi dimensioni, non utilizzare il suggerimento TABLOCK (che rimuoverà le ottimizzazioni di massa) o utilizzare una dimensione batch inferiore (che preserva le ottimizzazioni di massa).
Poiché i computer variano, ti consigliamo di testare varie dimensioni di batch con il caricamento dei dati per scoprire quale funziona meglio per te.
Personalmente vorrei solo inserire tutte le 695 righe in un singolo batch. L'ottimizzazione delle dimensioni del batch può fare una grande differenza quando si inseriscono molti dati.
4. Assicurati di aver bisogno della IDENTITY
colonna
Non so nulla del tuo modello di dati o requisiti, ma non cadere nella trappola dell'aggiunta di una IDENTITY
colonna a ogni tabella. Aaron Bertrand ha un articolo su questo chiamato Cattive abitudini da calciare: mettere una colonna IDENTITÀ su ogni tavolo . Per essere chiari, non sto dicendo che dovresti rimuovere la IDENTITY
colonna da questa tabella. Tuttavia, se si determina che la IDENTITY
colonna non è necessaria e la si rimuove, ciò potrebbe migliorare le prestazioni di inserimento.
5. Disabilitare indici o vincoli
Se stai caricando una grande quantità di dati in una tabella rispetto a quello che hai già, potrebbe essere più veloce disabilitare gli indici o i vincoli prima del caricamento e abilitarli dopo il caricamento. Per grandi quantità di dati, in genere è più inefficiente per SQL Server creare un indice tutto in una volta anziché quando i dati vengono caricati nella tabella. Sembra che tu abbia inserito 695 righe in una tabella con 11500 righe, quindi non consiglierei questa tecnica.
6. Considerare TF 610
Trace Flag 610 consente una registrazione minima in alcuni scenari aggiuntivi. Per la tua tabella con una IDENTITY
chiave cluster, otterrai una registrazione minima per qualsiasi nuova pagina di dati purché il tuo modello di recupero sia semplice o registrato in blocco. Ritengo che questa funzione non sia attiva per impostazione predefinita perché potrebbe ridurre le prestazioni su alcuni sistemi. Dovresti testare attentamente prima di abilitare questo flag di traccia. Il riferimento Microsoft raccomandato sembra essere ancora la Guida alle prestazioni di caricamento dei dati
Impatto I / O della registrazione minima sotto la bandiera di traccia 610
Quando si esegue il commit di una transazione di caricamento di massa che è stata minimamente registrata, tutte le pagine caricate devono essere scaricate sul disco prima del completamento del commit. Qualsiasi pagina svuotata non catturata da un'operazione di checkpoint precedente può creare una grande quantità di I / O casuali. In contrasto con un'operazione completamente registrata, che crea invece I / O sequenziali nelle scritture del registro e non richiede che le pagine caricate vengano scaricate sul disco al momento del commit.
Se lo scenario di caricamento è costituito da piccole operazioni di inserimento su btrees che non attraversano i limiti del punto di arresto e si dispone di un sistema I / O lento, l'utilizzo della registrazione minima può effettivamente rallentare la velocità di inserimento.
Per quanto posso dire, questo non ha nulla a che fare con il flag di traccia 610, ma piuttosto con una registrazione minima. Credo che la precedente citazione ROWS_PER_BATCH
sull'accordatura arrivasse a questo stesso concetto.
In conclusione, probabilmente non c'è molto che puoi fare per mettere a punto il tuo BULK INSERT
. Non sarei preoccupato per il numero di letture che hai osservato con il tuo inserto. SQL Server segnalerà le letture ogni volta che si inseriscono dati. Considera quanto segue molto semplice INSERT
:
DROP TABLE IF EXISTS X_TABLE;
CREATE TABLE X_TABLE (
VAL VARCHAR(1000) NOT NULL
);
SET STATISTICS IO, TIME ON;
INSERT INTO X_TABLE WITH (TABLOCK)
SELECT REPLICATE('Z', 1000)
FROM dbo.GetNums(10000); -- generate 10000 rows
Uscita da SET STATISTICS IO, TIME ON
:
Tabella "X_TABLE". Conteggio scansione 0, letture logiche 11428
Ho 11428 letture riportate ma non si tratta di informazioni fruibili. A volte il numero di letture riportate può essere ridotto con una registrazione minima, ma ovviamente la differenza non può essere tradotta direttamente in un miglioramento delle prestazioni.