viele jpa-entitäten "persistieren"

dermoritz

Bekanntes Mitglied
gibt es irgendeinen besonderen mechanismus Entity-Klassen-Instanzen in großen Mengen in die DB zu schreiben - per JPA? Ich kann mir vorstellen, dass ein
Code:
for each List<EntityKlasse> ek
...
em.persist(ek)
...

nicht sehr schnell ist, oder? Wär es ratsam große Stapel (ab welcher Größe könnte es Probleme geben?) an JPA vorbei in die DB zu schreiben?
 

dermoritz

Bekanntes Mitglied
mehrere Tausend in diesem speziellen Fall. aber für die Zukunft hätte ich gerne etwas allgemeinere Aussagen/Richtwerte/ Alternativen.
 

dermoritz

Bekanntes Mitglied
wie gesagt ich habe gemessen: mehrere Tausend - ist das problemeatisch? Hat jemand Erfahrung damit? Wann wird es problematisch? Es muss ja nicht jeder den selben Fehler machen und erst beim messen feststellen das es zu langsam ist im speziellen Fall, oder? Inwiefern spielt die Art der Entitäten/Anzahl betroffener Tabellen/Spalten eine Rolle? Meine Erfahrung mit normalen DB-Anwendungen ist, dass sowas völlig irrelevant ist in Relation zum Aufwand einzelner DB-Abfragen (also das einzige was wirklich Performance kostet ist die Anzahl der Abfragen und nicht deren Umfang).

Ab jetzt hätte ich bitte nur noch Aussagen die auf Erfahrung beruhen - auf die Idee das es problematisch werden könnte ab irgendeiner Zahl bin ich ja selber.
 

dermoritz

Bekanntes Mitglied
maki stell dir mal bitte den Thread ohne deine Antworten vor. Gehen dann Informationen verloren? ich hatte geantwortet "mehrere Tausend" weil du wissen wolltest "wieviele denn" - warum wolltest du das wissen? Du scheinst garkeine persönliche Erfahrung mit diesem Thema zu haben. Warum anwortest du?

Kannst du dir nicht vorstellen, dass irgendjemand Erfahrung mit dieser Thematik hat und sagen kann: "batch insert mit jpa ist immer problematisch" oder "es gibt bei bestimmten JPA Implementierungen spezielle Möglichkeiten". Oder "solange es nur wenige tausend sind gehts es".

Willst du mir sagen das deine Erfahrung auf dem Gebiet (offensichtlich keine) die maximale ist, die man bei dieser Frage bieten kann? Als Konsquenz: Jeder muss eigene Erfahrungen ("messen") machen und eben auch eigene Fehler machen um eine Lösung zu finden? Und ich dachte ein Forum ist für den Erfahrungsaustausch und nicht für: "mach deine eigenen Erfahrungen"-Antworten. Eigentlich sollten Moderatoren solche Art der Antworten unterbinden! Und eventuell den Thread löschen falls die Frage zu speziell ist. Aber ich denke das Erfahrungsberichte von anderen durchaus hilfreich sein könnten bei diesem Thema.
Meine Erfahrung zum Thema kommt von Kollegen: bei vielen hundertTausend/Millionen Einträgen sollte man auf keinen Fall JPA verwenden(mehrere Tage zu wenigen Stunden falls man JDBC verwendet)!
Hat noch jemand Lust seine Erfahrungen hier reinzuschreiben?
 
M

maki

Gast
moritz, was du dir vorstellen kannst oder nicht spielt doch gar keine Rolle.
Wie du dir herausnehmen kannst zu behaupten ich hätte damit keine Erfahrung ist mir schleierhaft.
Wenn du 10 Million gesagt hättest, hätte es einen Unterschied gemacht.

Tatsache ist, dass es keine Richtlinien gibt, weil es auf die Details ankommt, eben auf den konkreten Fall.

Dieser Thread ist nur ein Beispiel dafür, dass wenn du nicht die Antwort bekommst die du erwartest (zB. "Ab 10000 kein ORM") persönlich wirst und deinem gegnüber unterstellst keine Ahnung zu haben.

Ich hab auch schon 100000 Datensätze mit ORM in die DB geklopft, das ist nicht das Problem, das geht auch relativ schnell(anfangs geschätzte 5 Stunden, nach Optimierungen gemessene 3 Stunden), wenn man es richtig macht, kommt aber auf die DB Struktur an, auf die Transaktionengrößen, und auf die konfiguration des ORM.
Wer behauptet dass das nicht geht macht es schlicht falsch, aber wie gesagt,e skommt auf den konkreten Fall an.

Wie dem auch sei, hoffe du findest noch Antworten auf deine Fragen die dir besser gefallen, suche doch mal hier im Forum, das Thema gab schon mehrmals.
 

dermoritz

Bekanntes Mitglied
nun kann ich sagen Danke Maki das sind infos mit denen man zumindest weiterfragen kann und eine erste Vorstellung von der Problematik bekommt.

Dann gehts mal weiter: welche "details" sind denn entscheidend für die Performance? Welche Optimierung hast du in dem speziellen Fall vorgenommen, welche davon sollte man immer in Betracht ziehen?

in meinem speziellen Fall handelt es sich um 2 Tabellen (1:1) jeweils um die 10 spalten. In diese beiden Tabellen werden in unregelmäßigen Abständen mehrere 10000 Einträge importiert.
Ich hab die Sorge das die Persistence API bei 50000 "em.persist(instanz)" eben 50000 insert -Abfragen an die DB schickt - is das so? Oder wird sowas eventuel gepuffert und in Blöcken an die DB-geschickt? 50000 oder größe Blöcke in einer query in die db schreiben geht ja sehr schnell. Wenn man das in Blöcken in die Db schreiben könnte ist das Nadelöhr nur noch die Instanziierung der Objekt, die man aber aus konsistenzgründen braucht.
 
M

maki

Gast
Diese "Blöcke" sind einerseits sog. Batches, und andererseits deine Transaktionen, je nachdem, wieviel Statements da drinnen sind, ändert sich deren größe.
Die optimale Transaktionensgröße herauszufinden ist wichtig, diese hängt auch von der DB Konfig. ab, Transaktionen laufen meist auf temp. Tabellen, DBs haben die max. größe der Temp tabellen konfuguriert.
D.h. aber auch, dass u.U. nicht alles rückgängig (Rollback) gemacht werden kann.
Die Hibernate Doku hat ein extra Kapitel für batch inserts und deren konfiguration (Chapter 13. Batch processing), query caching abschalten kann auch helfen bei Speicehrproblemen (OutOfMemoryException)

Prinzipiell werden zwar 50000 inserts gemacht, diese könnten aber auch in "nur" 500 "Blöcken" (Batches) gesendet werden, wichtig wäre, ob nach jedem insert wieder selects ausgeführt werden müssten.
IMHO (aber geraten und nicht gemessen): 10000 Einträge in 2 Tabellen mit 1:1 Mapping sollten kein Problem darstellen, vorrausgesetzt es passiert nicht alle paar Minuten, aber wie gesagt, ist geraten/dahergeredet, Messen & testen für den Proof of Concept wäre da immer angesagt.

Das Problem mit normalen JDBC bzw. gleich das SQL Script in der DB ausführen am ORM vorbei ist bekannt, das ORM kennt die Änderungen nicht, müsste vorher erst runtergefahren werden.
 

dermoritz

Bekanntes Mitglied
nochmal danke!
ich hab mal gegoogelt nach "eclipselink batch processing" und siehe da da kann man was konfigurieren. Mal angenommen die default konfiguration reicht erstmal: Wie definiert man batches oder führt sie aus? Oder passiert das irgendwie automatisch? Theoretisch könnte ich zwischen tx.begin und tx.commit ja einige (tausend) em.flush oder em.persist unterbringen - werden die dann als batch-Abfrage ausgeführt oder gibt es trotzdem mehrere tausen insert-Abfragen die nur als eine Transaktion laufen?

edit: dank der hinweise hab ich das gefunden:
Using EclipseLink JPA Extensions (ELUG) - Eclipsepedia
Bei "eclipselink.jdbc.batch-writing" sieht man die Optionen die man setzen kann. Versteh ich das richtig: in meinem Falle (MySQL) würde ich "JDBC" nehmen? Und im Code würde ich vermutet mehrere persists (alle eines imports) in einer Transaktion zusammenfassen. Über die Konfiguration wäre dann geregelt wie groß die Blöcke sind in die das ganze gespalten wird. Ist das so korrekt?
 
Zuletzt bearbeitet:
M

maki

Gast
Bei "eclipselink.jdbc.batch-writing" sieht man die Optionen die man setzen kann. Versteh ich das richtig: in meinem Falle (MySQL) würde ich "JDBC" nehmen?
Ja, sehe ich auch so, habe aber keine Erfahrung mit Batches unter EclipseLink.
Die Batch size bestimmt eben die Anzahl der Statements die in einem Rutsch an die DB geschickt werden(das Netzwerk ist langsam, seltener aber dafür mehr schicken lohnt sich), Transaktionen dagegen wann Änderungen übernommen werden, beide größen würde ich durch testen ermitteln.
 

dermoritz

Bekanntes Mitglied
so nun hab ich das alles mal getestet aber es scheint nicht zu funktionieren: Aus 2 em.persist innerhalb einer Transaktion werden 2 insert queries gemacht.
Weiß jemand wie ich batch-writing mit eclipseLink benutzen kann? (Also mit batch meine ich mehrere inserts in eine Query zusammenzufassen.)


edit: mhm ich hab nochmal in der eclipselink anleitung gelesen:
"Batch writing can improve database performance by sending groups of INSERT, UPDATE, and DELETE statements to the database in a single transaction, rather than individually. "

Seh ich das richtig das batchwriting gar nichts macht? denn eine Gruppe von Inserts ind einer Transaktion hab ich ja schon durch meinen Code realisiert:

tx.begin
em.persist(1)
em.persist(2)
tx.commit
?
 
Zuletzt bearbeitet:

Siassei

Bekanntes Mitglied
Servus,

ich lese gerade mit und hätte da eine Anmerkung :)
"Batch writing can improve database performance by sending groups of INSERT, UPDATE, and DELETE statements to the database in a single transaction, rather than individually. "

Seh ich das richtig das batchwriting gar nichts macht? denn eine Gruppe von Inserts ind einer Transaktion hab ich ja schon durch meinen Code realisiert:

tx.begin
em.persist(1)
em.persist(2)
tx.commit
?
Deine Frage/Aussage verstehe ich jetzt nicht. Bist du dir sicher, dass du den englischen Text verstanden hast?
Da steht "Batch writing kann die Leistung steigern. Dies wird mittels zusammenfassen von mehreren z.B. Insert-Statements in ein Statment in der akt. Transaktion bewerkstelligt."

em.persist(..)
em.persist(..)

Das hätte erstmal zwei Statements zur folge. Batch writing erstellt aus dieser Gruppe von Statements eine einzige und schickt diese zur DB.

Gruß,
Thomas
 

dermoritz

Bekanntes Mitglied
Genau so hatte ich es zunächst verstanden, aber es funktioniert nicht es bleiben 2 insert-Queries. Und dann hab ich den Text nochmal gelesen und meine es heißt: "...durch senden von Gruppen von Insert-Anweisungen in einer Transaktion..."
Also die Beschleunigung kommt davon, dass nicht für jede Anweisung eine Transaktion aufgemacht wird, sondern mehrere Anweisungen in einer Transaktion ausgeführt weden.

Aber wie gesagt das erbibt eben irgendwie kein Sinn, denn dafür bräuchte man ja die Settings in der persistence.xml nicht setzen. Statements in einer Transaktion zusammenfassen geht ja allein über den Code?!

edit: ich glaube ich hab einen hinweis gefunden warum es nicht funktioniert:
"You should also not use IDENTITY sequencing, instead use TABLE sequencing, then you can make use of sequence preallocation, and batch writing. " (Old Nabble - EclipseLink - Users - Batch insert)

und

"Always use sequence number pre-allocation for best performance for inserts. SEQUENCE or TABLE sequencing should be used for optimal performance, not IDENTITY which does not allow pre-allocation." (Oracle TopLink (EclipseLink) JPA Performance Tuning)

Das hört sich nicht unplausibel an. Ich schätze der Persistence Provider kann etwas nur persistieren wenn am Ende eine ID rauskommt und bei Identity geht das eben nur wenn man die Dinger einzeln reinschiebt und nach jedem insert die letzte ID abfragt?!


Edit: hab inzwischen mal eine ID-Tabelle angelegt nur hat das gar nichts geholfen. Die Persistence APi fordert nun zwar Blöcke von IDs an (50, einstellbar) aber es werden immer noch 2 inserts generiert. Nun weiß ich nicht mehr weiter. eventuell müssen auch die Relationen der Tabellen untereinander bestimmten Anforderungen genügen damt sowas funktioniert?
Hat jemand noch Ideen?
 
Zuletzt bearbeitet:

Ähnliche Java Themen


Oben