Aktualisierung / Einfügen der Massendatenbank aus der CSV-Datei

8

Ich implementiere eine anwendungsspezifische Datenimportfunktion von einer Datenbank in eine andere.

Ich habe eine CSV-Datei mit beispielsweise 10000 Zeilen. Diese Zeilen müssen in die Datenbank eingefügt / aktualisiert werden.

Es kann vorkommen, dass einige Zeilen in der Datenbank vorhanden sind, was bedeutet, dass diese aktualisiert werden müssen. Wenn nicht in der Datenbank vorhanden, müssen diese eingefügt werden.

Eine mögliche Lösung besteht darin, dass ich eine Zeile nach der anderen lesen, den Eintrag in der Datenbank überprüfen und entsprechende Einfüge- / Aktualisierungsabfragen erstellen kann. Dieser Vorgang kann jedoch viel Zeit in Anspruch nehmen, um Abfragen zum Aktualisieren / Einfügen zu erstellen und in der Datenbank auszuführen. Manchmal enthält meine CSV-Datei Millionen von Datensätzen.

Gibt es einen anderen schnelleren Weg, um diese Funktion zu erreichen?


quelle
Versuchen Sie es in Teilen zu verarbeiten, sonst führt ein großer CSV-Wert auf einen Schlag dazu OutOfMemory!
@TheNewIdiot Das passiert nicht, wenn genügend Speicher wie ein anständiger Server verwendet wird, der mindestens 2 GB RAM für die JVM bereitstellt. Dies hängt auch von der Art der Daten in der CSV-Datei ab und davon, ob der Prozess in einem einzelnen Prozess oder neben anderen auf dem Server verarbeiteten ausgeführt wird.
@ Luiggi Mendoza: Ich stimme dir zu. Wir haben genug Speicher, um die große CSV-Datei in der Produktion zu verarbeiten.

Antworten:

7

In Oracle gibt es eine nette Technologie namens Externe Tabellen. In Ihrem Szenario, könnten Sie Ihre externen Klartext - Daten mit externen Tabellen aus der Datenbank zugreifen und aktualisieren Sie Ihre vorhandenen Daten in der Datenbank mit SQL - Anweisungen , die Sie lieben und werden verwendet , um - zum Beispiel INSERT, MERGEusw.

In den meisten Fällen ist die Verwendung von Oracle-Dienstprogrammen der beste Weg, um ETL durchzuführen. Und da Ihre Frage eher nach einer administrativen Frage klingt, empfehle ich Ihnen, meinen vorherigen Beitrag zu DBA Stack Exchange "Oracle-Datenbank von CSV aktualisieren" zu lesen .

UPDATE: Dieser Ansatz eignet sich sehr gut zum Lesen externer Daten in der Datenbank. Im Allgemeinen definieren Sie jedes Mal ein externes Datenformat, wenn Sie die Nur-Text-Datei mit neuem Format verarbeiten müssen. Sobald eine externe Tabelle erstellt wurde, können Sie sie wie eine echte Datenbanktabelle abfragen. Immer wenn neue Daten importiert werden müssen, ersetzen Sie einfach die zugrunde liegenden Dateien im laufenden Betrieb, ohne externe Tabellen neu erstellen zu müssen. Da externe Tabellen wie jede andere Datenbanktabelle abgefragt werden können, können Sie SQL-Anweisungen schreiben, um andere Datenbanktabellen zu füllen.

Der Aufwand für die Verwendung externer Tabellen ist im Vergleich zu anderen Techniken, die Sie manuell implementieren würden, normalerweise geringer, da diese Technologie unter Berücksichtigung der Oracle-Datenbankarchitektur unter Berücksichtigung der Leistung entwickelt wurde.

Yasir Arsanukaev
quelle
Ich bin damit einverstanden, dass dies eine der Lösungen ist, um mein Ziel zu erreichen. Wie kann dieser Ansatz für die dynamische CSV-Verarbeitung geeignet sein? Das heißt, mein Anwendungsbenutzer hat die Möglichkeit, mehrere Dateien mit unterschiedlichen Formaten hochzuladen (in diesem Fall müssen externe Geschichten im laufenden Betrieb erstellt werden). Eine CSV-Datei kann auch Daten enthalten, die in mehrere Tabellen eingefügt werden müssen.
1

Ich denke, Sie sollten SQL * Loader verwenden, um eine CSV-Datei in eine temporäre Tabelle zu laden, und dann die MERGE-Anweisung verwenden, um Daten in eine Arbeitstabelle einzufügen.
SQL * Loader bietet Ihnen mehr Flexibilität als externe Tabellen. Wenn Sie das direkte Laden von Pfaden verwenden, ist dies sehr schnell. Und MERGE wird genau das tun, was Sie brauchen - neue Datensätze einfügen und vorhandene aktualisieren.
Einige Links zum Starten:
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

Mindaugas Riauba
quelle
1
Wenn Sie Daten mit SQL Loader in die Datenbank laden , schreiben der DBWR-Prozess oder der SQL Loader-Prozess Puffer in Datendateien. Wenn Sie anschließend geladene Daten in andere Tabellen verschieben, führt die Datenbank eine weitere E / A durch. Ich denke nicht, dass diese zusätzliche Arbeit gerechtfertigt sein kann. Übrigens, wenn externe Tabellen den ORACLE_LOADER-Treiber verwenden, ist die Syntax zum Definieren des Eingabedatenformats dieselbe, die vom Dienstprogramm sqlldr verwendet wird, da sie im Wesentlichen dieselbe Technologie sind und daher austauschbar verwendet werden können. Externe Tabellen in diesem Szenario werden bevorzugt, da keine Daten zuerst in die Datenbank
geladen
Wie üblich lautet die Antwort "es kommt darauf an" :). In unserem Fall ist es normalerweise bequemer, zuerst in die temporäre Tabelle zu laden und später zu verarbeiten. Da die direkte Pfadlast keine Wiederholung erzeugt, sind zusätzliche E / A unter anderen Vorgängen fast unbemerkt. In anderen Fällen sind natürlich andere Methoden besser.
Mindaugas Riauba
0

Mit PreparedStatements können Einfüge- oder Aktualisierungsabfragen sehr schnell erstellt werden. Sie sollten drei haben PreparedStatements: eine zum Einfügen, eine zum Aktualisieren und eine zum Überprüfen, ob die Zeile bereits in der Tabelle enthalten ist. Wenn Sie in der Lage sind, die IDs zwischen der CSV-Datei und der neuen Datenbank gleich zu halten, sollte die Überprüfung, ob eine Zeile vorhanden ist, mithilfe des Felds primaryID ebenfalls sehr schnell erfolgen.

Die Verwendung eines Batch-Einsatzes kann zu einem Leistungsgewinn führen. Während Sie durch die CSV-Datei streamen, prüfen Sie, ob die Zeile bereits vorhanden ist, und führen dann entweder eine Aktualisierung durch oder fügen die Zeile Ihrem Befehl zum Batch-Einfügen hinzu. Sie sollten diese SO-Frage für den Geschwindigkeitsvergleich dieser beiden Ansätze überprüfen .

Wenn dieser Datenbankimport regelmäßig durchgeführt werden muss und die Leistung mit der oben beschriebenen Methode ein Problem darstellt, können Sie versuchen, die Aufgabe mit mehreren Arbeitsthreads zu bearbeiten. Verwenden Sie auf dem Computer, auf dem dieser Code ausgeführt wird, so viele Threads wie Prozessoren.

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

Jeder Thread erhält eine eigene DB-Verbindung, und während Ihr Code die Datei durchläuft, können CSV-Zeilen an die verschiedenen Threads übergeben werden. Dies ist viel komplizierter, daher würde ich dies nur tun, wenn mich die Leistungsanforderungen dazu zwingen würden.

Gemeinschaft
quelle
Danke für deine Antwort. Dies erfordert wiederum das Parsen von CSV-Dateien und das Auffüllen von Werten in vorbereitete Anweisungen. Beim Ansatz "Externe Tabellen" kann das Parsen von Dateien auf die Datenbankseite verschoben werden, wo sich die Anwendung nicht darum kümmern muss. Außerdem verwende ich JPA mit Ruhezustand in meiner Anwendung. Ich suche nach der Option, die die Kombination von JPA / Hibernate / Oracle sein kann, die kein Parsen von Dateien ermöglicht, gute Leistung, wartbar und flexibel.