567 messaggi dal 18 marzo 2002
Ciao,
ho scritto delle procedure in c# per importare dei file di testo di grosse dimensioni (anche 3 Gb)in SQL server. La struttura di questi file è abbastanza complessa essendo formati da varie tipologie di righe; in pratica leggo il file riga per riga ed in base al tipo riga faccio il parsing del tracciato e mi costruisco dinamicamente le query d'inserimento appropriate. Ogni tipologia di riga ha la propria tabella di database associata (sono circa 20 tabelle), comprensiva di primarykey e svariati indici.
Una procedura di importazione costruita così impiega molte ore per importare un intero file perchè deve eseguire decine di migliaia di query insert (a volte anche più di 100000); domanda: è previsto in SQL Server una modalità d'inserimento che mi permetta di abbattere drasticamente questi tempi ?

Grazie
1.976 messaggi dal 27 luglio 2005
Contributi
salve,
la modalita' nativa di inserimento storicamente piu' "performnte" e' effettuata in modalita' bulk, appunto tramite le api di bulk insert, offerte anche dal programma a linea di comando BCP.exe... queste api (e/o BCP.exe stesso) richiedono pero' come input dei file sui quali non sia necessario procedere ad operazioni di parsing o altro... vengono letti tramite le api anche in modalita' multithreaded procedendo quindi alle operazioni di insert...
nel tuo caso, potresti vedere come le funzionalita' di un pacchetto personalizzato SSIS, codificando task specifici per il parsing, possa assolvere il compito...
passando a BCP o SSIS avresti la funzionalita' aggiuntiva della possibilita' di schedulazione, che ti libera dalla necessita' di provvedere manualmente...
100.000 righe non sono proprio qualche cosa di mostruoso, ma sicuramente "interessante"... ad ogni modo, potresti verificare prima dell'importazione, che il database sia dimensionato fisicamente in modo da ospitare l'intero incremento di righe... dico questo perche' in caso contrario, dipendentemente dalle relative impostazioni di growth, potresti incorrere in molteplici step di accrescimento dei file, che oltre a comportare "molteplici sprechi di tempo", impongono una alta frammentazione dei file fisici risultanti, penalizzando ulteriormente le attivita' sul db...
saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php
567 messaggi dal 18 marzo 2002
Ciao Andrea,
ti ringrazio per la risposta esaustiva.
Ne approfitto per altri chiarimenti:
- per interfacciarmi a bulk insert da c# devo utilizzare l'oggetto SqlBulkCopy ?
- Se l'operazione di bulk insert non va a buon fine in che stato viene lasciato il database ? Devo fare delle operazioni di manutenzione in questo caso ?
- Non sempre i file da importare sono corretti o conformi al tracciato, ed in questo caso vorrei che il bulk insert terminasse lasciando o ripristinando il database allo stesso precedente all'operazione di imnport, senza intervenire sul db del cliente per ripristinarlo, è possibile ottenere questo ?

Grazie ancora
1.976 messaggi dal 27 luglio 2005
Contributi
PGH ha scritto:
Ciao Andrea,
ti ringrazio per la risposta esaustiva.
Ne approfitto per altri chiarimenti:
- per interfacciarmi a bulk insert da c# devo utilizzare l'oggetto SqlBulkCopy ?
- Se l'operazione di bulk insert non va a buon fine in che stato viene lasciato il database ? Devo fare delle operazioni di manutenzione in questo caso ?


leggi anche http://msdn.microsoft.com/en-us/library/tchktcdk(v=vs.80).aspx ...
diciamo che "dipende" da come vuoi considerare "l'intera importazione"... se le 100.000 righe che vai ad importare sono da considerarsi "1 unico blocco logico di importazione", allora devi gestire il tutto in un unica transazione esplicita, cosi' che, se il tuo "job" fallisce all'ultimo "batch" di altri 4999 andati a buon fine, potrai tranquillamente chiamare il rollback lasciando il db nello stato consistente e pulito, cioe' "o tutte le righe o nessuna" saranno atomicamente importate...



- Non sempre i file da importare sono corretti o conformi al tracciato, ed in questo caso vorrei che il bulk insert terminasse lasciando o ripristinando il database allo stesso precedente all'operazione di imnport, senza intervenire sul db del cliente per ripristinarlo, è possibile ottenere questo ?

con le transazioni esplicite assolvi anche questo compito...
solo che sarebbe preferibile verificare la "validita'" dei file prima di caricare il server... sarebbe uno spreco indicibile caricare 999.999 righe valide per poi dover effettuarne il rollback perche' la millionesima riga non e' valida...

fai anche attenzione alle dimensioni del transaction log, che potrebbe lievitare mostruosamente...

per coprirti le spalle in caso di disaster recovery, tecnicamente potresti:
1)fare backup completo prima dell'importazione
2)cambiare il recovery model del db da "full" a "bulk logged"
3)caricare i dati
4)cambiare di nuovo il recovery model a full
5)backup completo del db dopo il ripristino a full del recovery model

cosi' da essere "quasi sicuro" di esserti parato per bene :)

per le performance, vedi anche le potenzialita' del batchsize, in modo da operare scelte "intelligenti"... vedi ad esempio http://www.sqlbi.com/wp-content/uploads/SqlBulkCopy-Performance-1.0.pdf

saluti

Andrea Montanari
http://www.hotelsole.com - http://www.hotelsole.com/asql/index.php

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.