8 Stimmen

Warum macht das Abfrage-Caching mit Hibernate die Abfrage zehnmal langsamer?

Ich bin derzeit experimentieren mit EJB3 als Vorstudie für ein großes Projekt bei der Arbeit. Eines der Dinge, die ich suche, ist Abfrage-Caching.

Ich habe ein sehr einfaches Domänenmodell mit JPA-Annotationen, einer @Local-Geschäftsschnittstelle und einer @Stateless-Implementierung in einem EJB-JAR erstellt, das zusammen mit einer sehr einfachen Webapp in einer EAR bereitgestellt wird, um einige grundlegende Tests durchzuführen. Die EAR wird in der Standardkonfiguration von JBoss 5.0.1 ohne Änderungen bereitgestellt. Dies war sehr einfach und funktionierte wie erwartet.

Bei meinem letzten Test, bei dem es um die Zwischenspeicherung von Abfragen ging, erhielt ich jedoch einige seltsame Ergebnisse:

  • Ich habe eine Domänenklasse, die nur eine ID und einen String-Wert zuordnet, und habe etwa 10000 Zeilen in dieser bestimmten Tabelle erstellt
  • In der Business Bean gibt es eine sehr einfache Abfrage: SELECT m FROM MyClass m
  • Ohne Zwischenspeicher dauert die Ausführung im Durchschnitt 400 ms.
  • Bei aktiviertem Abfrage-Cache (durch Hinweise auf die Abfrage) dauert die erste Ausführung natürlich etwas länger, etwa 1200 ms. Die nächsten Ausführungen dauern im Durchschnitt 3500ms!

Das verwirrte mich, also aktivierte ich show_sql von Hibernate, um mir das Protokoll anzusehen. Ohne Cache und bei der ersten Ausführung mit aktiviertem Cache wird ein SELECT protokolliert, wie erwartet. Wenn ich Cache-Treffer erhalten sollte, protokolliert Hibernate ein SELECT für jede Zeile in der Datenbanktabelle.

Das würde sicherlich die langsame Ausführungszeit erklären, aber kann mir jemand sagen, warum das passiert?

0 Stimmen

In meinem Blog finden Sie einige nützliche Informationen über den Abfrage-Cache hier: * tech.puredanger.com/2009/07/10/hibernate-query-cache

17voto

Matt Solnit Punkte 29896

Die Funktionsweise des Abfrage-Caches besteht darin, dass er nur die ID's der von der Abfrage zurückgegebenen Objekte. Ihre anfängliche SELECT-Anweisung könnte also alle Objekte zurückgeben, und Hibernate wird sie Ihnen zurückgeben und sich die IDs merken.

Bei der nächsten Abfrage geht Hibernate jedoch die Liste der IDs durch und stellt fest, dass es die tatsächlichen Daten materialisieren muss. Also geht es zurück zur Datenbank, um den Rest zu erhalten. Und es macht ein SELECT pro Zeile, was genau das ist, was Sie sehen.

Bevor Sie jetzt denken: "Diese Funktion ist offensichtlich kaputt": Der Grund, warum es so funktioniert, ist, dass der Query Cache so konzipiert ist, dass er mit dem Second Level Cache zusammenarbeitet. Wenn die Objekte nach der ersten Abfrage im L2-Cache gespeichert sind, sucht Hibernate stattdessen dort, um die Pro-ID-Anforderungen zu erfüllen.

Ich empfehle Ihnen dringend, das Buch zu lesen Java-Persistenz mit Hibernate um mehr darüber zu erfahren. Kapitel 13 befasst sich insbesondere mit der Optimierung von Abfragen und der effektiven Nutzung des Cache.

1 Stimmen

Gut, ich werde auch versuchen, den Cache der 2. Ebene zu aktivieren. Ich liebe diesen Ort :-)

0 Stimmen

Dieses Buch ist schon ein paar Jahre alt, ist es noch aktuell?

0 Stimmen

Gute Frage, Nathan. Ich verwende Hibernate 3.2, und alles scheint mir auf dem neuesten Stand zu sein. Das Buch deckt auch alle JPA 1.0-Annotationen ab und enthält auch eine Einführung in JBoss Seam. Gibt es irgendwelche wichtigen neuen Funktionen in Hibernate 3.3, die vielleicht nicht abgedeckt werden?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X