Warum verkürzt die Query-Caching-Funktion mit Hibernate die Abfrage um das Zehnfache?

8

Ich experimentiere derzeit mit EJB3 als Vorstudie für ein großes Projekt bei der Arbeit. Eines der Dinge, die ich untersuche, ist das Query-Caching.

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

Mein letzter Test beinhaltete jedoch das Zwischenspeichern von Abfragen, und ich habe einige seltsame Ergebnisse erhalten:

  • Ich habe eine Domain-Klasse, die nur eine ID und einen String-Wert zuordnet und ungefähr 10000 Zeilen in dieser bestimmten Tabelle erstellt hat
  • In der Business-Bean gibt es eine sehr einfache Abfrage, SELECT m FROM MyClass m
  • Ohne Cache wird das im Durchschnitt in ungefähr 400ms ausgeführt
  • Wenn der Abfragecache aktiviert ist (durch Hinweise auf die Abfrage), dauert die erste Ausführung natürlich etwas länger, etwa 1200ms. Die nächsten Ausführungen dauern durchschnittlich 3500ms!

Das hat mich verwirrt, also habe ich Hibernate's show_sql aktiviert, um das Log zu sehen. Uncached und bei der ersten Ausführung mit aktiviertem Cache wird wie erwartet ein SELECT protokolliert. Wenn ich Cache-Treffer erhalten soll, 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?

    
Nils-Petter Nilsen 20.05.2009, 20:24
quelle

1 Antwort

16

Der Abfragecache funktioniert so, dass er nur die ID der von der Abfrage zurückgegebenen Objekte zwischenspeichert. Ihre ursprüngliche SELECT-Anweisung kann also alle Objekte zurückgeben, und Hibernate gibt sie Ihnen zurück und erinnert sich an die IDs.

Beim nächsten Ausführen der Abfrage durchläuft Hibernate jedoch die Liste der IDs und stellt fest, dass sie die tatsächlichen Daten materialisieren muss. Also geht es zurück in die Datenbank, um den Rest zu bekommen. Und es macht eine SELECT pro Zeile, die genau das ist, was Sie sehen.

Nun, bevor Sie denken, "diese Funktion ist offensichtlich defekt", liegt der Grund dafür, 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 werden, sucht Hibernate stattdessen dort nach den Anforderungen für die ID-Anforderung.

Ich empfehle Ihnen dringend, das Buch Java Persistence with Hibernate zu lesen, um mehr darüber zu erfahren . Kapitel 13 behandelt insbesondere die Optimierung von Abfragen und die effektive Verwendung des Caches.

    
Matt Solnit 20.05.2009, 20:28
quelle

Tags und Links