2017-05-11 4 views
0

Ich habe ein Design-Problem. Ich habe eine Datenbank mit Millionen von Datensätzen, die ich aktualisieren muss.JDBC Update Millionen von Datensätzen auf Oracle-Datenbank

Wir werden JDBC verwenden, weil wir einige Berechnungen durchführen müssen, um neue Felder zu berechnen.

Es ist ein One-Go, und ich werde es nicht mehr brauchen. Also habe ich über etwas Einfaches nachgedacht. Ich wollte neue Tabellen erstellen und die alten löschen, aber die DBA will nicht, weil die Notwendigkeit für Speicher wäre riesig.

Ich muss etwa 80 Millionen Zeilen verarbeiten und für jede Zeile 3 Felder zu aktualisieren.

Würde ein einfacher jdbc-Ansatz mit einem setFetchSize (1000) zum Beispiel funktionieren?

ich meine wählen a, b, c von veränderbar für update; dann das Update ...

Wäre ein JDBC-Programm in der Lage, die Arbeitslast zu unterstützen?

Ich habe auch über SpringBatch oder EasyBatch nachgedacht. Aber ich frage mich, ob es sich lohnt, die Zeit für einen einzigen Anlauf zu untersuchen (und einige sehr kurze Zeitlinien).

Was sind Ihre Erfahrungen damit?

+0

ist die Information benötigt, um die Updates alle in der Datenbank enthalten zu tun? (Formel wird verwendet) oder wenn Sie gesagt haben, dass eine Verarbeitung durchgeführt werden muss, liegt das daran, dass einige der benötigten Informationen für Aktualisierungen lokal sind? – xQbert

+0

Hallo. Nein, die Informationen für das Update sind nicht in der Datenbank enthalten. Ich muss die Datenzeile lesen, dann einen externen Dienst aufrufen, um die berechneten Werte abzurufen, und dann 3 Felder der Zeilen mit den berechneten Werten aktualisieren. – Gilles

+1

@Gilles Wie lange musst du das erreichen? Sie werden Daten in Java ziehen und für jede Zeile einen externen Dienst aufrufen und dann die Datenbank aktualisieren. Lassen Sie uns so tun, als könnten Sie das in 10ms pro Zeile machen, was ich bezweifle, dass Sie dazu in der Lage wären. Es dauert immer noch 9,25 Tage, um den Prozess abzuschließen. Erweitere es von dort. Wenn es 100ms pro Zeile dauert, sind es jetzt 92,5 Tage. Wenn es auf diese Weise geschehen muss, wissen Sie am besten, worauf Sie sich einlassen. – unleashed

Antwort

0

Ich denke, dass Sie dies in JDBC tun können. Ich würde etwas wie das folgende vorschlagen:

  • Erstellen Sie zwei oder drei Gewinde. Jeder Thread führt Folgendes durch:
  • Erstellen Sie eine Verbindung.
  • Erstellen Sie eine vorbereitete Anweisung, die eine disjunkte Untergruppe der Zeilen abruft
  • Legen Sie die Abrufgröße auf 100 oder so fest. Auf jeden Fall weniger als 1000.
  • Eine Update-Anweisung
  • Führen Sie die Abfrage
  • Iterate über das Ergebnis gesetzt
  • Für jede Zeile Batch fügen Sie die Zeile
  • Nach Fetch-Größe Reihen der Batch-
  • ausführen zu aktualisieren

Nehmen wir an, die Abrufgröße ist 100. Die erste Ausführung wird eine Rundreise machen, die Zeit braucht. Während das passiert, gehen Sie einen anderen Thread. Wenn eine Ausführung die Verarbeitung zurückgibt, führen die nächsten 100 Zeilen keinen Datenbank-Umlauf aus. Die Zeilen wurden bereits abgerufen und die Aktualisierungen werden gebündelt, sodass keine Datenbankumgehung durchgeführt wird. Nach 100 Zeilen führen Sie den Stapel aus, der eine Rundreise durchführt und so die Fäden wechselt. Dann werden 100 weitere Zeilen abgerufen, die die Threads wechseln. Ich bin mir nicht sicher, ob zwei oder drei Threads optimal wären, aber wenn ich raten müsste, würde ich drei ausprobieren.

Aber das oben genannte nimmt an, dass die Maschine nur einen einzelnen Hardware-Thread hat, der nicht wahr ist. Die meisten CPUs unterstützen 12 oder mehr Hardware-Threads, sodass ich tatsächlich 30 oder mehr Threads verwenden würde, je nachdem, was die Hardware unterstützen kann. Selbst mit mehreren CPUs wollen Sie wahrscheinlich nicht mehr als 50 oder mehr Threads, da dies zu Konflikten in der Datenbank führen wird.

Obiges geht davon aus, dass der externe Dienst schnell ist, viel schneller als die Datenbank. Wenn nicht, dann wird jede Zeile auf den externen Dienst warten. In diesem Fall mehr Threads.Da die Aktualisierungen die Datenbank langsamer treffen, ist die Thread-Konkurrenz in der Datenbank weniger bedenklich.

Eine Möglichkeit, die Abfrageergebnisse in disjunkte Teilmengen zu unterteilen ist wie folgt:

SELECT c1, c2, etc, row 
FROM (SELECT c1, c2, etc, ROWNUM FROM ...) 
WHERE MOD(row, number_of_partitions) = ? 

dann die Abfrage param von 0 bis number_of_partitions gesetzt - 1, eine für jeden Thread. Sie müssen dies als Unterabfrage tun, damit ROWNUM richtig funktioniert.

Verwenden Sie keine aktualisierbaren Ergebnissätze. Die Leistung wird miserabel sein, garantiert.

Verwandte Themen