Hibernate: Joins und Performance

Status
Nicht offen für weitere Antworten.

Babba_BLuBB

Aktives Mitglied
Hallo zusammen,

ich hab hier mal eine grundsätzliche Frage zur Verwendung von Joins in Hibernate. Ich dachte immer, dass die Verwendung von Joins grundsätzlich immer zu einem Performancegewinn führt, wenn man mehrere zusammenhängende Sachen aus verschiedenen Tabellen laden will bzw. mehrere persistierte Instanzen, die in Beziehung zueinander stehen.

Jetzt hab ich heute mal bissel mit Hibernate rumgespielt und musste feststellen, dass Joins nicht immer zu einem Performancegewinn führen. Ich habe mir eine Klasse A gemacht, die beliebig viele Beziehungen zu einer Klasse B aufnehmen kann. Also eine unidirektionale 1:N Beziehung zwischen A und B.

Dann hab ich 100 Instanzen der Klasse A gemacht, jeder dieser Instanzen 500 Instanzen der Klasse B zugeordnet und den ganzen Krams in eine Datenbank gesichert. Danach wollte ich alles wieder auf zwei Arten aus der Datenbank laden und danach die Ladezeiten vergleichen: Einmal ohne HQL/Criteria und einmal mit HQL unter Verwendung eines Joins.

Ich hatte die Erwartung, dass die Variante mit dem Join eigentlich schneller sein müsste, weil ja nur ein SQL-Query an die Datenbank geht. Die Variante ohne Join muss ja 100 Queries für die A-Instanzen absetzen und dann je A-Instanz wieder 1 Query für die Liste von zugeordneten B-Instanzen.

Als ich das ganze dann laufen lies musste ich feststellen, dass beide Varianten genau gleich lang brauchen.

Jetzt bin ich bissel verdutzt... Gibt es dafür eine logische Erklärung?

Grüße und danke schon mal im Vorraus
 
S

SlaterB

Gast
> Gibt es dafür eine logische Erklärung?

falsche Messung/ Interpretation?
poste doch zumindest deine HQL/ SQL-Kommandos + was dich ungefähr zu deinen Aussagen kommen läßt

> Die Variante ohne Join muss ja 100 Queries für die A-Instanzen absetzen

eine reicht

----

allgemein kann ein Join auch zu Langsamkein führen, zumindest aufgrund der Datenmenge,
wenn Klasse A 10 Attribute hat + Liste von 500 B und Klasse B nur 2,
dann würde bei einem Join 500x Klasse A + B geladen werden, also 500x 12 = 6000 Werte,

lädt man dagegen erst das A-Objekt, dann sind das nur 10 Werte, und die 500 B-Objekte für sich auch nur 1000 Werte,
hier würde man durch zwei Query also massiv Datenmengen sparen,
ob das dann langsamer oder schneller ist hängt von diversen Faktoren ab
 

byte

Top Contributor
Sicher, dass Du ein Fetch Join gemacht hast?
SQL:
select distinct a from A a left join fetch a.b

Ohne das Fetch initialisiert Hibernate die Bs nicht. Sie werden dann beim ersten Zugriff per Select geladen.
 

Babba_BLuBB

Aktives Mitglied
Hallo und schon mal danke für die Antworten.
Anbei die Sachen, die ich bisher so habe.

Ich habe mir zwei Klassen zum Testen erstellt. Das angehängte Bild "005" enthält ein Klassendiagramm. Ich habe dann verschiedene Testläufe gemacht, in denen ich alle persistierten Instanzen auf unterschiedliche Arten wieder aus der Datenbank geladen habe.

Erster Test: In der Datenbank befinden sich 14000 Parent-Instanzen (siehe Klassendiagramm) mit je einer assoziierten Child-Instanz.

Über Parent-Instanzen die assoziierten Child-Instanzen laden
- ueber Getter: 10867 ms
- ueber HQL mit Join: 1088 ms (also: "from Parent p join fetch p.children")
- ueber Criteria API mit Join: 1248 ms

Über Child-Instanzen die assoziierten Parent-Insanzen laden
- ueber Getter: 3823 ms
- ueber HQL mit Join: 869 ms (also: "from Child c join fetch c.parent")
- ueber Criteria API mit Join: 731 ms

Diese Ergebnisse erscheinen mir teilweise logisch. Ohne Join muss Hibernate 14001 Selects an die Datenbank absetzen. Also im ersten Fall ein Select um alle Parent-Instanzen zu beziehen und dann für je dieser Instanzen 1 Select um an die Liste der zugehörigen Child-Instanzen zu kommen.

So weit so gut. Aber warum braucht man im ersten Fall über die Getter 10867ms und im zweiten Fall nur noch 3823ms, obwohl in beiden Fällen meiner Meinung nach 14001 Selects an die Datenbank gehen.
 

Anhänge

  • 005.jpg
    005.jpg
    29,8 KB · Aufrufe: 33
S

SlaterB

Gast
wenn die Childs geladen sind, dann sind auch die 14.000 Parent-Ids bekannt,
und die Parents werden standardmäißg gewiss nicht einzeln geladen, sondern immer eine gewisse Menge auf einmal,
jedenfalls ergeben sich einfache Queries
from Parent where id in (id-List)

andersrum siehts viel schwerer aus, man hat nur die Parents, aber keine Id-Listen für die Childs,
hier ist es viel fraglicher, ob gleich optimierend für mehrere Parents die Childs zusammen gelade werden können,
denn während es überschaubar ist, z.B. gleich zu 10 Childs 10 Parents in einer Query zu laden, können zu jedem Parent potentiell tausende Childs vorhanden sein,
wer will da gleich für 10 Parents anfragen?

selbst wenn man diese 'fetch-size' außer acht läßt,
sind die DB-Anfragen vom Parent aus immer noch komplizierter, da ja wie gesagt die Ids der Childs unbekannt sind,
die Querys lauten also
from Child where parentId = id
oder
from Child where parentId in (id-List)


hmm, ok, die beiden Queries sehen doch nicht so viel anders aus ;) ,
und ein Index ist wohl für keine der Id-Spalten vorhanden

dann wäre nur noch die Frage der fetch-size,
teste doch mal mit einer DB, die Queries loggt, bzw. schalte in Hibernate das Log ein:
Code:
<hibernate-configuration>
    <session-factory>
    
[..]
		<!-- Miscellaneous Settings -->
		
		<!-- print all generated SQL to the console -->
		<property name="hibernate.show_sql">false</property>

[..]

		<!-- set the default batch size for batch fetching -->
		<property name="hibernate.default_batch_fetch_size">100</property>

oder es liegt an was ganz anderem ;)
 

byte

Top Contributor
So weit so gut. Aber warum braucht man im ersten Fall über die Getter 10867ms und im zweiten Fall nur noch 3823ms, obwohl in beiden Fällen meiner Meinung nach 14001 Selects an die Datenbank gehen.

Das lässt sich per Ferndiagnose schwer sagen. Am besten guckst Du Dir das erzeugte SQL an, dann bist Du schlauer.

Ich nehme an, Du hast eine gravierende Sache bei Deinem Test nicht beachtet: ManyToOne und OneToOne wird von Hibernate direkt mitgeladen. Lädst Du also alle Children, dann werden auch direkt alle Parents geladen. Hibernate lädt die dabei über zusätzliche Selects. Diese Selects gehen nicht erst raus, wenn Du den Getter aufrufst, sondern schon direkt beim Laden der Children.
Anders siehts aus, wenn Du die Parents lädst, die ja ein OneToMany oder ManyToMany auf Children haben. Die Collections werden nicht automatisch geladen (ausser Du machst ein Fetch Join). Die Collections werden dann initialisiert, wenn Du über die Collection iterierst.
 

Babba_BLuBB

Aktives Mitglied
DManyToOne und OneToOne wird von Hibernate direkt mitgeladen. Lädst Du also alle Children, dann werden auch direkt alle Parents geladen. Hibernate lädt die dabei über zusätzliche Selects.

Dazu muss Hibernate aber doch auch die vollen 14001 Selects an die Datenbank stellen, oder? Daher müsste doch dann auch die Laufzeit der ganzen Geschichte relativ unabhängig davon sein, ob Hibernate eine zu-1-Beziehung direkt mitläd oder eine zu-N-Beziehung mit nur einem Eintrag erst beim Aufruf des entsprechenden Getters läd.

Oder kann Hibernate beim direkten Laden von zu-1-Beziehungen noch irgendwie was rumoptimieren?
 
S

SlaterB

Gast
schalt doch einfach das Log ein und schau dir die Query an
 

byte

Top Contributor
Dazu muss Hibernate aber doch auch die vollen 14001 Selects an die Datenbank stellen, oder? Daher müsste doch dann auch die Laufzeit der ganzen Geschichte relativ unabhängig davon sein, ob Hibernate eine zu-1-Beziehung direkt mitläd oder eine zu-N-Beziehung mit nur einem Eintrag erst beim Aufruf des entsprechenden Getters läd.

Oder kann Hibernate beim direkten Laden von zu-1-Beziehungen noch irgendwie was rumoptimieren?

Bin mir nicht sicher, was Hibernate daraus macht. Das weisst Du, wenn Du das SQL anschaust.
Könnte sein, dass SlaterB recht hat und Hibernate schlau genug ist, die Parents mit wenigen Selects zu holen, da die IDs der Parents ja bekannt sind.

Wäre nett, wenn Du das Ergebnis mal posten würdest. Für gewöhnlich joine ich solche Parents direkt rein, um die zusätzlichen Selects zu sparen. Aber es würde mich auch mal interessieren, was Hibernate daraus macht.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
D Probleme bei Left Joins mit Hibernate createCriterias() Data Tier 2
T Hibernate/Spring JPA: eigene ID generieren Data Tier 5
Avalon @ManyToOne Hibernate oder JPA? Data Tier 5
D Hibernate Hibernate mit MariaDB Data Tier 1
ToBJo Hibernate Glassfish deploy mit Hibernate schlägt fehl Data Tier 1
C JPA Hibernate Map<String,String> richtig mappen Data Tier 2
S JPA Hibernate Search & EclipseLink (oder OpenJPA) Data Tier 0
R JPA Probleme mit Wechsel von EclipseLink auf Hibernate Data Tier 4
ARadauer Hibernate Entität readonly laden... Data Tier 1
G Hibernate SQL in Hibernate: Keine Parameter mit Index? Data Tier 2
P Wildfly + Hibernate + SQL Server Data Tier 0
E JPA Hibernate Query mit Timestamp hat seltsames Verhalten Data Tier 1
M Eclipse 4 RCP Hibernate Problem Data Tier 3
C Hibernate ProgressBar updaten mit Daten aus Hibernate Data Tier 4
B Hibernate und MySQL testen Data Tier 8
I Hibernate HQL: generiertes SQL ausgeben Data Tier 1
R mapping-file für hibernate zum Überschreiben der Annotationen Data Tier 7
R Hibernate Hibernate und Logback Data Tier 2
R Hibernate möchte Schema zwei mal undeployen Data Tier 2
F Hibernate Hibernate / JPA Data Tier 4
E Hibernate: Session vs EntityManager Data Tier 3
C Hibernate Hibernate Code Generation Data Tier 3
S Hibernate Mehrfachverbindung mit Hibernate Data Tier 3
M Hibernate Einstiegsfrage Data Tier 5
M Exception in thread "main" org.hibernate.MappingException: java.lang.ClassNotFoundException: Message Data Tier 4
S Hibernate Einstieg in Hibernate 3.2 sinnvoll? Data Tier 8
P JPA Eigene Vererbungsstrategie mit JPA / Hibernate Data Tier 2
J Hibernate Problem bei Master-Detail-Tabellen Data Tier 5
Y Jboss seam-hibernate-jpa Data Tier 5
RaoulDuke Hibernate Map<String,String> mit Annotations mappen Data Tier 2
M Hibernate Hibernate with GWT Data Tier 4
C Hibernate JPA mysql db erstellen Data Tier 4
M Hibernate Hibernate liest Daten zu oft aus! Data Tier 16
pg1337 Hibernate Fragen Data Tier 11
D Hibernate probleme mit Verlinkungstabelle Data Tier 4
2 Hibernate Annotations Data Tier 7
G Hibernate select update no wait Data Tier 8
Z Hibernate: Many-To-Many nur eine bestimmte Spalte Data Tier 3
K Hibernate - Envers - Erzeugung der SQL Skripte Data Tier 4
G Hibernate 1:n Beziehung mit Vererbung Data Tier 5
D Hibernate-Criteria-API (Projections und MAX-Funktion) Data Tier 6
L Hibernate: failed to lazily initialize a collection of role Data Tier 3
S Hibernate hibernate.cfg.xml Data Tier 14
D JPA vs Hibernate.cfg und Entitymanager Data Tier 6
H Hibernate - Mapping für Enumeration Data Tier 1
R Hibernate Criteria Abfrageproblem Data Tier 2
A Hibernate und jdbc zusammen Data Tier 4
D Mit Hibernate aus JUnit ein DB-Schema erzeugen Data Tier 6
S [Hibernate] No Persistence provider for EntityManager Data Tier 5
B Problem mit org.hibernate.LazyInitializationException Data Tier 11
G Hibernate HQL und Interface Data Tier 4
G JSF Hibernate no session or session was closed Data Tier 12
T JPA2/Hibernate: Many-to-Many-Relation wird u.a. beim löschen nicht aktualisiert Data Tier 14
S (Hibernate) Mapping einer Datenbanktabelle mit mehreren Fremdschlüssel Data Tier 7
X [Hibernate] Zusammengesetzte Entities möglich? Data Tier 7
N Hibernate Fake? Data Tier 2
S Problem beim Insert mit Hibernate Data Tier 9
V Hibernate Projection Data Tier 2
T org.hibernate.impl.SessionFactoryImpl Memory Leak Data Tier 10
G Hibernate Composite key Data Tier 11
X [Hibernate] Connection Pool - MinSize ? Data Tier 2
R Hibernate Criteria OR Data Tier 2
T hibernate/jpa abgefragte Listen immer mit Null-Werten gefüllt Data Tier 8
X [Hibernate] Anderen Connection Pool - Vorschläge? Data Tier 3
ARadauer Hibernate DDL Loggen Data Tier 6
G Hibernate abfrage Collection Data Tier 3
X [Hibernate] ReverseEngineering - Eigene Strategy verwenden? Data Tier 3
R Hibernate Criteria .group größer als Data Tier 5
R Hibernate daten laden Data Tier 7
H [Hibernate]1:1 Beziehung Data Tier 8
H [Hibernate]No CurrentSessionContext configured! Data Tier 6
X [Hibernate] Lässt sich die Dauer eines SELECTs loggen? Data Tier 4
R Hibernate n:n Relationtabelle mit Date Data Tier 3
H [Hibernate] Unknown Entity Data Tier 3
H [Hibernate] Configuration Data Tier 3
C [Hibernate] Generierung von hbm.xml to Java Data Tier 4
lumo Eclipse & JPA & Hibernate & Derby Data Tier 5
J Zufallsauswahl aus ResultList bei JPA(Hibernate) / Performance Data Tier 3
M Hibernate: Datum 0001-01-01 erzeugt null-Datum Data Tier 4
G Datenbankzugriff mit Hibernate Data Tier 7
Y Hibernate - Angabe des Schemas Data Tier 6
LadyMilka (Hibernate) in Criteria implizierter Join durch Subquery's Data Tier 8
M Hibernate Mehr als 1 Object speichern? Data Tier 18
M Unerklärliche Hibernate Exception Data Tier 20
LadyMilka (Hibernate) subquery in FROM-Clause Data Tier 9
haemi Viele DTOs in hibernate IdentityMap Data Tier 3
LadyMilka (hibernate) UNION dem Dialekt hinzufügen Data Tier 3
M Hibernate + Oracle 10g XE Data Tier 3
lumo Hibernate - entity class not found Data Tier 5
P SQL PRoblem Hibernate? Data Tier 8
J Vererbung mit JPA / Hibernate - pro/contra Data Tier 3
T JBoss/Hibernate: Abfrage dauert lang + hohe CPU? Data Tier 19
7 Hibernate-Abfrage (SubSelect im FROM) Data Tier 2
G Hibernate: many-to-one - Verwaiste Datensätze löschen Data Tier 2
G Layer für Datenbankzugriff Hibernate Data Tier 5
G Hibernate Zwischentabelle Data Tier 2
Java.getSkill() Hibernate und Spalte vom Typ xml Data Tier 6
G Hibernate 0...1 : 1 Beziehung Data Tier 6
G Hibernate mehrere @oneToone Data Tier 2
G Hibernate 1:n, 1:1 Data Tier 26

Ähnliche Java Themen

Neue Themen


Oben