Kann Hibernate in leistungsempfindlichen Anwendungen verwendet werden?
Sehe ich performance-Probleme mit dem abrufen von mehreren Instanzen von Objekten, die viele Beziehungen zu anderen Objekten. Ich bin mit Spring und Hibernate - JPA-Implementierung mit MySQL. Das Problem ist, dass bei der Ausführung einer JPA-query, Hibernate nicht automatisch an andere Tische. Dies ergibt n*r + 1 SQL-Abfragen, wobei n die Anzahl der Objekte, die abgefragt werden, und r ist die Anzahl der Beziehungen.
Beispiel eine Person lebt, an eine Adresse, hat viele Hobbys, und besuchte viele Länder:
@Entity
public class Person {
@Id public Integer personId;
public String name;
@ManyToOne public Address address;
@ManyToMany public Set<Hobby> hobbies;
@ManyToMany public Set<Country> countriesVisited;
}
Wenn ich eine JPA-query, um alle Personen, die mit Namen Bob, und es gibt 100 Bobs in der Datenbank:
SELECT p FROM Person p WHERE p.name='Bob'
Hibernate übersetzt, 301 SQL-Abfragen:
SELECT ... FROM Person WHERE name='Bob'
SELECT ... FROM Address WHERE personId=1
SELECT ... FROM Address WHERE personId=2
...
SELECT ... FROM Hobby WHERE personId=1
SELECT ... FROM Hobby WHERE personId=2
...
SELECT ... FROM Country WHERE personId=1
SELECT ... FROM Country WHERE personId=2
...
Entsprechend der Hibernate FAQ (hier und hier), die Lösung ist, um anzugeben, LEFT JOIN-oder LEFT OUTER JOIN (die für viele-zu-viele) in der Abfrage. So nun meine Abfrage sieht wie folgt aus:
SELECT p, a, h, c FROM Person p
LEFT JOIN p.address a LEFT OUTER JOIN p.hobbies h LEFT OUTER JOIN p.countriesVisited c
WHERE p.name = 'Bob'
Dies funktioniert, aber es scheint ein Fehler zu sein, wenn es mehr als eine LEFT OUTER JOIN in diesem Fall Hibernate ist falsch auf der Suche für eine nicht-existente Säule:
could not read column value from result set: personId69_2_; Column 'personId69_2_' not found.
Fehler Verhalten erscheint, die möglicherweise angesprochen Hibernate Core bug HHH-3636. Leider ist die Fehlerbehebung ist nicht Teil von jedem veröffentlicht Hibernate JAR. Ich habe meine Bewerbung vor der snapshot-build, aber das Fehler-Verhalten ist immer noch vorhanden. Ich habe auch gebaut, meine eigene Hibernate-Core-JAR von den neuesten code in das repository und das Fehler-Verhalten ist immer noch vorhanden. Also vielleicht HHH-3636 nicht dieses.
Diese Hibernate performance-Einschränkung ist sehr frustrierend. Wenn ich die Abfrage für 1000 Objekte dann 1000*r + 1 SQL-Abfragen an der Datenbank vorgenommen werden. In meinem Fall habe ich 8 Beziehungen also ich bekomme 8001 SQL-Abfragen, die Ergebnisse in schreckliche Leistung. Die offizielle Hibernate-Lösung ist left join alle Beziehungen. Aber dies ist nicht möglich mit mehr als einer viele-zu-viele-Beziehungen aufgrund der Fehler-Verhalten. So bin ich stecken mit der linken schließt sich für viele-zu-eins-Beziehungen und n*r+1 Abfragen durch die viele-zu-viele-Beziehungen. Ich plan Einreichen, den LEFT-OUTER-JOIN-problem ist wie ein Hibernate-bug, aber in der Zwischenzeit mein Kunde braucht eine app, die hat eine angemessene Leistung. Derzeit benutze ich eine Kombination von batch fetch (BatchSize), ehcache und benutzerdefinierte in-memory-caching, aber die Leistung ist noch ziemlich schlecht (es verbessert abrufen 5000 Objekte von 30 bis 8 Sekunden). Die Quintessenz ist, dass zu viele SQL-Abfragen auf die Datenbank.
So, meine Fragen, ist es möglich, Überwintern in der performance-sensitive Anwendungen, bei denen Tabellen haben mehrfache Beziehungen zu einander? Ich würde gerne hören, wie erfolgreich Hibernate verwendet-Adresse der Leistung. Sollte ich von hand schreiben von SQL (was irgendwie Niederlagen der Zweck der Verwendung von Hibernate)? Sollte ich de-normalisieren mein Datenbank-schema zu reduzieren, die Anzahl der verknüpften Tabellen? Sollte ich nicht mit Hibernate, wenn ich brauche eine schnelle Abfrageleistung? Gibt es etwas schnellere?
InformationsquelleAutor der Frage Steve Kuo | 2009-03-16
Du musst angemeldet sein, um einen Kommentar abzugeben.
Siehe meine Antwort auf Ihre andere Fragewenn Sie Lesen Sie die gesamte FAQ verlinkt zu:
Siehe die Tipps auf Verbesserung der Leistung. Wenn Sie nicht vorsichtig mit joins, Sie werden am Ende mit Kartesisches Produkt Probleme.
InformationsquelleAutor der Antwort toolkit
Neben der "fetch" - Strategie, die Sie könnte auch versuchen, die Einstellung batch-fetch-Größe in hibernate-Eigenschaften, so dass er den Beitritt Abfragen nicht einzeln, sondern im Stapel.
In Ihrem appContext.xml:
Also statt:
Erhalten Sie:
InformationsquelleAutor der Antwort serg
Haben Sie versucht, die "join" fetch-Strategie für die Sammlungen?
InformationsquelleAutor der Antwort Maurice Perry
Wenn Sie benötigen ein feature von Hibernate, und diese Funktion ist buggy, haben Sie zwei Möglichkeiten:
a) Senden Sie eine bugrequest und verwenden Sie einen workaround (langsam oder handgeschriebene sql), bis der Fehler behoben ist, das wird eine Weile dauern
b) einen Antrag auf bugrequest zusammen mit einem bugfix und tests. (natürlich könnte man verwenden Sie einfach den bugfix und überspringen Sie die bugrequest und test Teil).
InformationsquelleAutor der Antwort Jens Schauder