# Große Datenmengen mit JPA 2.x verarbeiten



## alexbt (8. Jul 2011)

Hallo,

folgende Ausgangssituation:
Ich habe vor eine Postgres-Datenbank aufzusetzen mit "realtiv" großen Tabellen:

3 Tabellen mit 50-100 Mio. Datensätze mit relativ kurzer Satzlänge (serial,char(5),dec(10,5),timestamp)
2 Tabellen mit relativ langer Satzlänge (10x char(50),10xchar(5),3xdec(18,2))

Diese Tabellen werden mit der Zeit auf ca. 300 Mio. Datensätze anwachsen und es können auch 1-2 Tabellen dazu kommen.

Meine Idee war die Anbindung an Java mit JPA 2.x (hier geplant ist Eclipselink) zu machen.
Mir ist klar, dass wenn ich diese Daten als Entities-Objekte erzeuge und dann innerhalb von Java verarbeiten will, mir der Heap sehr schnell voll ist, bzw. ich ein Großrechner bräuchte...

Die einzige Lösung die mir dazu einfällt wäre nativen Sql als temp-Table auf der Datenbank "abzulegen" per nativen Sql weiterzuverarbeiten und das resultset dann als ObjectList nach Java zu holen.
Bei der Lösung geht aber sehr viel wenn nicht alle Vorteile von JPA verloren.
Hat dazu jemand ne clevere Idee? Vielleicht stehe ich auch nur auf dem Schlauch...

Danke im Voraus!
Alex


----------



## gman (8. Jul 2011)

> und das resultset dann als ObjectList nach Java zu holen



Ob du jetzt die Ergebnisse als "ObjectList" nach Java holst oder als JPA-Entity-Pojos dürfte
keinen Unterschied machen. Die Frage ist wohl eher ob deine Java-App generell mit so vielen
Daten umgehen kann. Die Anbindung an die DB spielt da weniger eine Rolle, wenn ich dein
Problem richtig verstanden habe.


----------



## alexbt (8. Jul 2011)

Also so wie ich es mir überlegt hatte macht es schon ein Unterschied ob ich Pojo oder java jpa objekten verwende, denn ich wollte die criteria api nutzen damit ich schon Fehler bei compiliern merke.
Außerdem finde ich es eine feine sache wenn ich nur die gemappten Klassen mit den Tabellen synchron halten muss, bei Änderungen und bequem Tabellen oder Klassen generieren lassen kann... etc. ich finde das schon moderner als nativen sql gegen die datenbank zu schicken.


----------



## Ebenius (8. Jul 2011)

Die Länge der Tabellen ist eigentlich Nebensache. Wenn Du die Instanzen nicht alle im Heap vorhältst, dann bekommst Du kein Problem. Was soll denn das Programm mit der großen Tabelle anstellen?

Ebenius


----------



## alexbt (8. Jul 2011)

Also dachte bisher,dass es schon einen Unterschied macht, ob ich 1000 objekte mit 2 char (1) attribute erzeuge oder viele gewisse Attribute pro Objekt habe.Das dürfte schon einen Unterschied machen für den Heap.

Das Programm sollte z.b.  alle Sätze laden und abhängig von der Attributbelegung verändern kopieren etc. und bestimmte Objekte wieder speichern.


----------



## Ebenius (8. Jul 2011)

Na die Frage ist doch, ob das Programm dazu alle Objekte halten muss, oder ob es im Abarbeiten eines JPQL-/Criteria-Query-Results geladene Objekte modifizieren und dann vergessen kann. Die Result-List einer JPA-Query ist ja auch nix anderes als ein ResultSet.

Oder denkst Du mit Deiner Frage in eine ganz andere Richtung?

Ebenius


----------



## gman (8. Jul 2011)

> Das Programm sollte z.b. alle Sätze laden und abhängig von der Attributbelegung verändern kopieren etc. und bestimmte Objekte wieder speichern.



Kann man das nicht über SQL-Skripte abbilden? Diese kann man auch über JPA an die DB schicken. Dann
kannst du jeweils das aussuchen was du gerade brauchst.


----------



## alexbt (9. Jul 2011)

Ebenius hat gesagt.:


> Na die Frage ist doch, ob das Programm dazu alle Objekte halten muss, oder ob es im Abarbeiten eines JPQL-/Criteria-Query-Results geladene Objekte modifizieren und dann vergessen kann. Die Result-List einer JPA-Query ist ja auch nix anderes als ein ResultSet.
> 
> Oder denkst Du mit Deiner Frage in eine ganz andere Richtung?
> 
> Ebenius



Mometan würde ich annehmen, dass ich alle Objekte im Heap halten muss um einige Anwendungen durchzuführen, aber vielleicht stehe ich auch eben nur auf dem Schlauch...

Ein einfaches Beispiel für nur 1 Tabelle/Entity mit dem genannten Problem:
1.) selektiere alle Objekte einer Klasse
2.) erhöhe das Betragsfeld abhängig vom Datumsfeld um einen bestimmten Faktor in einer FOR-Schleife abhängig von wechselnden Datums-Einschränkungen und char-Einschränkungen mehrmals 
3.) selektiere Objekte ab einem bestimmten errechneten Wert des Betragsfelds und verändere eine char-Feld bei diesen Objekten
4.) persistiere nur das geänderte Char-Feld dieser Objekte in der "echten" Tabelle, aber nicht das Betragsfeld

Wenn ich das nur mit Sql mache ist es klar:
1.) select * from EchteTabelle into temp table tmp1
2.) for-Schleife mit update temp1 set betrag = ... where ...
3.) update temp1 set bez=... where ...
4.) update-join zwischen EchteTabelle und temp1 und schreibe geändertes char-feld in EchteTabelle
5.) drop temp1

Wie mache ich sowas mit JPA 2.x bzw. JPA Criteria API?
Ein (spontaner und vielleicht nicht so intelligenter) Ansatz mit Criteria-API wäre:
1.) ein einfaches select um die Objekte zu erzeugen, wobei mir hier schon der Heap in die Quere kommt
Falls es keine Heap-Problem gäbe...
2.) for-Schleife über die Objekte, wobei ich die "Original"(gemappten)-Objekte vorher kopieren müsste, damit ich den echten Wert des Betragsfeldes nicht ändere
3.+4.) wieder eine Schleife über die Orignal-Objekte mit Vergleich zu den jeweilig kopierten Objekt (z.B. über ID-Feld) um die Bezeichnung beim Original-Objekten abh. vom Wert des Betragsfeldes des jeweilig kopierten Objekts zu ändern
5.) persist Original-Objekte


----------



## MrWhite (9. Jul 2011)

Ich rate bei grossen Datenmengen grundsaetzlich davon ab, diese prozedural (ihr wisst, was ich meine) in Java zu verarbeiten, besonders wenn noch die Performanz eine Rolle spielt.

Eine Aneinanderreihung von SQLs, vom Groben ins Feine, ist meist wesentlich performanter. Auf Datenbankunabhaengigkeit wuerde ich in solchen Faellen auch pfeiffen, das wird sowieso ueberschaetzt. Welcher Kunde mit solchen Datenmengen kommt schon auf die Idee, die DB zu wechseln?

Dein Plan, updates in eine for-Schleife auszufuehren halte ich fuer eine schlechte Idee. Mach einen Update fuer alle oder mehrere Updates fuer Gruppen, bei denen nach unterschiedlichen Kriterien geupdated wird.


----------



## gman (9. Jul 2011)

Ich stimme MrWhite zu. SQL wurde ja eben dafür entwickelt auf Mengen von Daten zu arbeiten.


----------



## alexbt (9. Jul 2011)

MrWhite hat gesagt.:


> Ich rate bei grossen Datenmengen grundsaetzlich davon ab, diese prozedural (ihr wisst, was ich meine) in Java zu verarbeiten, besonders wenn noch die Performanz eine Rolle spielt.
> 
> Eine Aneinanderreihung von SQLs, vom Groben ins Feine, ist meist wesentlich performanter. Auf Datenbankunabhaengigkeit wuerde ich in solchen Faellen auch pfeiffen, das wird sowieso ueberschaetzt. Welcher Kunde mit solchen Datenmengen kommt schon auf die Idee, die DB zu wechseln?



Dass der von mir dargelegt Ablauf in diesem Beispiel proedural ist, stimmt natürlich. 
Mir geht es weniger um den bequemen Wechsel zwischen Datenbankherstellern bzw. Sql-Dialekten, sondern um Typsicherheit durch Criteria Api, das bequeme Handling zur Modellierung/Erzeugung von Entity-Klassen/Tabellen und deren Synchronisierung, etc.

Vom Groben -> Feine wäre ja genau meine Lösung mit nativem Sql, oder verstehe ich dich falsch?
1) grobe Vorselektion -> in temp table, 
2) danach einzelne Updates auf den temp table, wobei hier jedes Update von dem Ergebnis des vorherigen Updates abhängig ist
3) char-Bezeichnung update-join in EchteTabelle



MrWhite hat gesagt.:


> Dein Plan, updates in eine for-Schleife auszufuehren halte ich fuer eine schlechte Idee. Mach einen Update fuer alle oder mehrere Updates fuer Gruppen, bei denen nach unterschiedlichen Kriterien geupdated wird.



Vielleicht war meine Beschreibung 
                 "2.) for-Schleife mit update temp1 set betrag = ... where ..."
etwas missverständlich. Ich wüßte nicht wie ich ohne for-Schleife dynamisch bestimmen kann wie oft geupdatet wird.
Also z.b. 3x Integer: jahr_beg,jahr_end und i
z.b.
jahr_beg=2011 und jahr_end=2040

"Pseudocode":
for i = jahr_beg to jahr_end

// faktor und limit sind zwei double, welche innerhalb der for-schleife abh. von i belegt werden

update tmp1 set betrag = betrag * faktor
where datum <= mdy(12,31,i)
and betrag <= limit

end for


Wobei meine Frage weniger ist, ob ich das mit oder ohne for-Schleife und nativem Sql lösen kann, sondern wie kann ich solche und ähnliche Probleme mit großen Datenmengen elegant mit/innerhalb JPA 2.x mit Criteria Api lösen, wenn ich nicht ständig dynamische Strings als nativen Sql erzeugen und zur Datenbank schicken will?


----------



## MrWhite (10. Jul 2011)

Deine Vorgehensweise ist dann vermutlich fuer deinen Use-Case ok.

Elegant finde ich es allerdings nicht, einen Abstraktionslayer fuer etwas zu verwenden, was die DB am besten selbst erledigt. Versteck den Ablauf in einer Prozedur auf der DB und call die einfach mit Hibernate. Ist doch die simpelste Loesung.


----------



## alexbt (10. Jul 2011)

MrWhite hat gesagt.:


> Deine Vorgehensweise ist dann vermutlich fuer deinen Use-Case ok.
> 
> Elegant finde ich es allerdings nicht, einen Abstraktionslayer fuer etwas zu verwenden, was die DB am besten selbst erledigt. Versteck den Ablauf in einer Prozedur auf der DB und call die einfach mit Hibernate. Ist doch die simpelste Loesung.



Vielleicht ist das genau die Stelle beim Schlauch auf der ich stehe ...  

Ich hatte bisher nicht an stored procedure's gedacht.
Wenn ich dich richtig verstehe, wäre dein Vorschlag diesen Teil der Logik als stored procedure abzulegen.
Der Vorteil wäre natürlich, dass ich keine Heap-Probleme mehr hätte. Der Nachteil wäre, dass ich 1) abhängig von der möglichen Sprachen der Datenbank bin (wobei es bei Postgres einige Auswahl gäbe).
Hierzu gleich mal ne Frage, hat jemand schon pl/java mit Postgres 9.0 ausprobiert oder ist pl/pgsql der Standard bzw. das Übliche in so einem Fall? 
Eine andere Nachteil aus meiner Sicht wäre, dass ich die Logik zur Aufbereitung an 2 Stellen hätte und somit auch immer 2 Stellen ändern müsste. Wobei ich dabei vielleicht auch völlig falsch liege, habe bisher nicht soviel Erfahrung mit der Kombination aus JPA+stored procedures.


----------



## alexbt (13. Jul 2011)

alexbt hat gesagt.:


> Hierzu gleich mal ne Frage, hat jemand schon pl/java mit Postgres 9.0 ausprobiert oder ist pl/pgsql der Standard bzw. das Übliche in so einem Fall?



Kann mir jemand noch einen Tipp, welche Sprache im Zusammenhang mit postgres am meisten Sinn machen, bzw. was ich bei der Wahl bedenken sollte?


----------

