Aggiornamento / inserimento di database in blocco dal file CSV


8

Sto implementando la funzionalità di importazione dei dati specifici dell'applicazione da un database all'altro.

Ho un file CSV contenente dire 10000 righe. Queste righe devono essere inserite / aggiornate nel database.

Potrebbe esserci il caso in cui un paio di righe potrebbero essere presenti nel database, il che significa che è necessario aggiornarle. Se non presenti nel database, è necessario inserirli.

Una possibile soluzione è che, posso leggere una per una riga, controllare la voce nel database e creare query di inserimento / aggiornamento di conseguenza. Ma questo processo potrebbe richiedere molto tempo per creare query di aggiornamento / inserimento ed eseguirle nel database. Alcune volte il mio file CSV può contenere milioni di record.

C'è un altro modo più veloce per ottenere questa funzione?

java  oracle 

Prova a elaborarlo in parti o altrimenti si otterrà una lettura CSV di grandi dimensioni in un colpo solo OutOfMemory!

@TheNewIdiot che non accadrà se si utilizza abbastanza memoria come un server decente che destinerà almeno 2 GB di RAM alla JVM. Dipenderà anche dal tipo di dati nel file CSV e se il processo verrà eseguito in un singolo processo o accanto ad altri elaborati nel server.

@Luiggi Mendoza: sono d'accordo con te. Abbiamo memoria sufficiente per elaborare il file CSV di grandi dimensioni in produzione.

Risposte:


7

C'è una bella tecnologia disponibile in Oracle chiamata tabelle esterne. Nel tuo scenario, puoi accedere ai tuoi dati di testo in chiaro esterni usando le tabelle esterne dall'interno del database e aggiornare i tuoi dati esistenti nel database con le istruzioni SQL che ami e a cui sei abituato, ad esempio INSERT, MERGEecc.

Nella maggior parte dei casi, l'utilizzo delle utility fornite da Oracle è il modo migliore per eseguire ETL. E poiché la tua domanda suona più come amministrativa, ti consiglio di guardare il mio precedente post su DBA Stack Exchange "Aggiorna database Oracle da CSV" .

AGGIORNAMENTO: questo approccio funziona piuttosto bene per la lettura di dati esterni nel database. Generalmente, si definisce il formato di dati esterni ogni volta che è necessario elaborare il file di testo semplice che ha un nuovo formato. Una volta creata una tabella esterna, puoi interrogarla come una vera tabella di database. Ogni volta che ci sono nuovi dati da importare, devi semplicemente sostituire i file sottostanti al volo senza dover ricreare tabelle esterne. Poiché una tabella esterna può essere interrogata come qualsiasi altra tabella di database, è possibile scrivere istruzioni SQL per popolare altre tabelle di database.

Il sovraccarico dell'utilizzo di tabelle esterne è generalmente inferiore rispetto ad altre tecniche che implementereste manualmente poiché questa tecnologia è stata progettata tenendo conto delle prestazioni tenendo conto dell'architettura del database Oracle.


Sono d'accordo che questa è una delle soluzioni per raggiungere il mio obiettivo. Come può essere adatto questo approccio all'elaborazione CSV dinamica? Significa che il mio utente dell'applicazione ha l'opportunità di caricare più file con formati diversi (in questo caso devono essere creati racconti esterni al volo). Inoltre, un file CSV può contenere dati che devono essere popolati in più tabelle.

1

Penso che dovresti usare SQL * Loader per caricare il file CSV nella tabella temporanea e quindi utilizzare l'istruzione MERGE per inserire i dati nella tabella di lavoro.
SQL * Loader ti darà maggiore flessibilità rispetto alle tabelle esterne e se si utilizza il caricamento diretto del percorso è molto veloce. E MERGE farà esattamente ciò di cui hai bisogno: INSERISCI nuovi record e AGGIORNA quelli esistenti.
Coppia di link per iniziare:
http://docs.oracle.com/cd/B19306_01/server.102/b14215/ldr_concepts.htm
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016 htm


1
Quando si caricano dati nel database utilizzando SQL Loader, il processo DBWR o il processo SQL Loader scrive buffer nei file di dati. Quando successivamente si spostano i dati caricati su altre tabelle, il database esegue un altro I / O. Non penso che questo lavoro extra possa essere giustificato. Inoltre, quando le tabelle esterne utilizzano il driver ORACLE_LOADER, la sintassi per la definizione del formato dei dati di input è la stessa utilizzata dall'utilità sqlldr perché essenzialmente sono la stessa tecnologia e quindi possono essere utilizzati in modo intercambiabile. Le tabelle esterne in questo scenario sono preferite poiché non è necessario caricare prima i dati nel database
Yasir Arsanukaev

Come sempre, la risposta è "dipende" :). Nel nostro caso è generalmente più conveniente caricare prima nella tabella temporanea ed elaborare successivamente. Poiché il caricamento del percorso diretto non genera ripetizioni, l'I / O aggiuntivo è quasi impercettibile tra le altre operazioni. In altri casi ovviamente altri metodi saranno migliori.
Mindaugas Riauba,

0

PreparedStatements renderà molto veloce la creazione di query di inserimento o aggiornamento. Dovresti avere tre PreparedStatements: uno per l'inserimento, uno per l'aggiornamento e uno per verificare se la riga è già nella tabella. Se riesci a mantenere gli ID uguali tra il file CSV e il nuovo database, anche la verifica della presenza di una riga utilizzando il campo ID primario dovrebbe essere molto veloce.

L'uso di un inserto batch può offrire un miglioramento delle prestazioni. Durante lo streaming del file CSV, verifichi quindi se la riga è già presente e quindi esegui un aggiornamento o aggiungi la riga al comando di inserimento batch. È necessario controllare questa domanda SO per il confronto rapido di questi due approcci.

Se l'importazione di questo database è qualcosa che deve essere eseguita regolarmente e le prestazioni sono un problema utilizzando il metodo che ho descritto sopra, puoi provare a gestire l'attività con più thread di lavoro. Utilizzare tanti thread quanti sono i processori sulla macchina che esegue questo codice.

  int nThreads = Runtime.getRuntime().availableProcessors();

Ogni thread ottiene la propria connessione DB e mentre il codice scorre attraverso il file, le linee di CSV potrebbero essere passate ai vari thread. Questo è molto più complicato, quindi lo farei solo se i requisiti di prestazione mi costringessero a farlo.


Grazie per la tua risposta. Ancora una volta, ciò richiederà l'analisi del file CSV e il popolamento dei valori in istruzioni preparate. Con l'approccio 'Tabelle esterne', vedo che l'analisi dei file può essere spostata sul lato Database dove l'applicazione non ha bisogno di preoccuparsene. Inoltre, sto usando JPA con Hibernate nella mia applicazione. Sto cercando l'opzione che può essere la combinazione di JPA / Hibernate / Oracle che facilita l'analisi dei file, le buone prestazioni, la manutenzione e la flessibilità.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.