2009-11-23 19 views
9

Ich hatte vor kurzem ein ziemlich seltsames Phänomen. Er musste eine Anzahl erhalten, die Joins über mehrere Tabellen mit unterschiedlichen WHERE-Bedingungen enthielt. Ich habe die Abfrage zuerst mit der Kriterien-API von Hibernate implementiert. Es hat die angeforderte vorbereitete SQL-Anweisung korrekt erstellt, war aber ziemlich langsam. Re-implementiert dann die gesamte Abfrage mit HQL. War ziemlich unangenehm, aber das Ergebnis war viel schneller als mit der Kriterien-API. Kennt jemand den Grund für dieses Verhalten? Ich nahm an, dass das Criteria- und das HQL-Framework die gleiche Codebasis verwenden, um es in SQL zu transformieren. HierHibernate Query vs Kriterien Leistung

ist die Abfrage:

select count(*) from R r where r.ISREPLACEDBY = 0 
and r.STATUS='OK' and r.A = ? 
and r.C in 
    (select distinct RC from CX cx where cx.FROMDATE >= ? and cx.FROMDATE <=?) 
+0

Können Sie die HQL und Kriterien Abfragen zeigen? –

+0

Die Abfrage hängt von den Parametern ab. Eines der einfacheren Statements ist das folgende: Wählen Sie count (*) aus R r wobei r.ISREPLACEDBY = 0 und r.STATUS = 'OK' und r.A =? und r.C in (select distinct RC von CX cx where cx.FROMDATE> =? und cx.FROMDATE <=?) – bertolami

Antwort

17

Ich denke, ich habe endlich den Grund gefunden. Es scheint, dass das Kriterium api bei jeder Ausführung einer vorbereiteten Anweisung neue Variablennamen erzeugt. Die Datenbank (in unserem Fall DB2) berechnet dann jedes Mal, wenn die Anweisung ausgeführt wird, einen neuen Abfrageausführungsplan. Auf der anderen Seite verwendet HQL dieselben Variablennamen, so dass die Datenbank die Abfrageausführungspläne erneut verwenden kann.

0

ich in der Regel glauben, dass HQL sehr nahe optimal ist, wie es mit ein paar Auswechslungen fast gerade SQL ist. Ich würde annehmen, dass die Übersetzung von HQL zu SQL nur eine Ersetzung ist; Die Kriterien-API generiert wahrscheinlich HQL, um dann transformiert zu werden. Generell ist HQL die beste Wahl.

+2

Tatsächlich übersetzt Criteria direkt in SQL. z.B. Criterion.toSqlString – qualidafial

+0

Das ist eigentlich nicht wahr. Es erzeugt zuerst HQL, die dann analysiert wird. – mnp

0

Hibernate Kriterien verwenden Reflexion SQL Statments zu erzeugen

+0

Ein weiteres Problem mit der Kriterien-API besteht darin, dass es jedes Mal die HQL generiert (auch weil es jedes Mal anders sein könnte). Dieser HQL wird jedes Mal auch in SQL übersetzt. Diese Übersetzung versucht, einige der Tokens über den Klassenlader (z. B. generatedBla0) zu laden, der eine ClassNotFoundException auslöst. Dies ist eine ziemlich teure Operation, da sie alle Klassenlader durchläuft, bevor der letzte eine Ausnahme auslösen kann und auch einige Sperren im Klassenlader beinhaltet, die die Leistung stark beeinflussen. Vergessen zu erwähnen, dass aufgrund eines Fehlers Integer in den SQL statt in Params eingefügt werden können. – mnp

3

Kriterien sollte in der Theorie haben weniger Overhead als eine HQL-Abfrage (mit Ausnahme der benannten Abfragen, die ich bekommen). Dies liegt daran, dass Kriterien nichts analysieren müssen. HQL-Abfragen werden mit einem ANTLR-basierten Parser analysiert und dann wird der resultierende AST in SQL umgewandelt. Mit HQL/JPAQL können Sie jedoch benannte Abfragen definieren, in denen das SQL generiert wird, wenn die SessionFactory gestartet wird. Theoretisch haben benannte Abfragen weniger Overhead als Kriterien. in Bezug auf die SQL-Generation Kopf So haben wir:

  1. Named HQL/JPAQL Abfrage - SQL-Generierung nur einmal passiert.
  2. Kriterien - Keine Analyse vor dem Generieren erforderlich.
  3. (nicht benannte) HQL/JPAQL-Abfrage - Parse, dann generieren. Das heißt, die Wahl einer Abfragetechnik basierend auf dem Overhead von Parsing und SQL-Generierung ist meiner Meinung nach ein Fehler. Dieser Overhead ist normalerweise sehr klein im Vergleich zur Ausführung einer echten Abfrage auf einem echten Datenbankserver mit echten Daten. Wenn dieser Overhead tatsächlich beim Profiling der App angezeigt wird, sollten Sie vielleicht zu einer benannten Abfrage wechseln.

Hier sind die Dinge, die ich berücksichtigen, wenn zwischen Kriterien und HQL/JPAQL Entscheidung:

  • Zuerst müssen Sie entscheiden, ob Sie Ihre eine Abhängigkeit mit, auf Hibernate-proprietäre API OK sind in Code. JPA hat keine Kriterien.
  • Die Kriterien sind wirklich gut im Umgang mit vielen optionalen Suchparametern , wie Sie auf einer typischen Webseite mit einem Multi-Parameter "Suchformular" finden können. Mit HQL tendieren Entwickler dazu, where-Klausel Ausdrücke mit StringBuilder (vermeiden Sie dies!). Mit Kriterien müssen Sie das nicht tun.
  • HQL/JPAQL kann für die meisten anderen Dinge verwendet werden, weil der Code tendenziell kleiner und einfacher für Entwickler zu verstehen ist.
  • Wirklich häufige Abfragen können in benannte Abfragen umgewandelt werden, wenn Sie HQL verwenden. Ich ziehe es vor, dies später nach einer Profilerstellung zu tun.

können Sie hier einige zusätzliche Informationen http://tech.puredanger.com/2009/07/10/hibernate-query-cache/ lesen