Entfernen redundanter Joins, die von Unterabfragen in JPA-Kriterien erzeugt werden

9

Ich muss einfach die folgende MySQL-Abfrage mit JPA-Kriterien ausführen (Abrufen einer Liste von Zuständen (aus state_table ) basierend auf einem angegebenen Ländernamen (in country )).

%Vor%

Ich habe die folgende JPA-Kriterienabfrage geschrieben.

%Vor%

Diese Kriterienabfrage erzeugt unnötigerweise einen redundanten Join in der generierten SQL-Abfrage wie folgt.

%Vor%

Wie zu bemerken ist, gibt es einen redundanten Join AND (t0.country_id = t1.country_id )) .

Dies wird durch root.get(StateTable_.countryId).get(Country_.countryId) verursacht, was einen inneren Join in der folgenden Zeile in der oben angegebenen Kriterienabfrage bedeutet. Dies sollte in diesem Fall nicht unnötig passieren.

%Vor%

Wie wird diese überflüssige Verbindung entfernt?

Ich verwende JPA 2.0 von EclipseLink 2.3.2.

Anstatt eine Unterabfrage in diesem Fall zu verwenden, kann sie besser mit einem Join zwischen diesen beiden Tabellen behandelt werden, aber das Schreiben solcher Unterabfragen ohne redundante Joins in ihnen sollte möglich sein, da es eine ziemlich einfache Sache ist / sub>

EDIT 1:

Eine äquivalente EXISTS() -Abfrage funktioniert folgendermaßen:

%Vor%

Daraus ergibt sich die folgende korrekte SQL-Abfrage, die wiederum an MySQL delegiert wird.

%Vor%

Es wurde keine Möglichkeit gefunden, eine äquivalente IN() -Abfrage zu generieren.

EDIT 2:

Das folgende JPQL,

%Vor%

erzeugt die richtige IN() Unterabfrage.

%Vor%

Daraus könnte ich mir die folgende Kriterienabfrage vorstellen.

%Vor%

Aber es schlägt mit der folgenden Ausnahme zur Laufzeit fehl.

%Vor%

Ich kann keinen Grund für diese Ausnahme sehen.

EDIT 3:

Dieselbe Kriterienabfrage in der letzten Revision - die, die mit der Ausnahme fehlschlägt, funktioniert gut ohne jegliche Änderung in JPA von Hibernate (4.2.7 final) mit genau der gleichen Tabellenbeziehung in einem anderen Projekt.

Erzeugt die folgende korrekte SQL-Abfrage.

%Vor%

Daher sollte unter EclipseLink etwas Unzuverlässiges passieren.

Sollte ich davon ausgehen, dass dies ein Fehler in EclipseLink in der Kriterien-API ist?

EDIT 4:

Die Verwendung von EXISTS() , wie oben gezeigt, führt auch zu einem redundanten Join, wenn die Abfrageanweisung umgekehrt ist wie

%Vor%

JPA, das von Hibernate bereitgestellt wird (ich verwende derzeit 4.2.7 final), generiert Abfrageanweisungen, wie wir es normalerweise ohne solche redundanten Joins erwarten.

Dies ist eine sehr einfache Abfrage und es ist ziemlich schwer zu glauben, dass dies ein Versehen in EclipseLink ist. Es scheint mir, dass ich etwas falsch machen muss, etwas offensichtliches, sehr grundlegendes vermissen muss. Bitte klären.

Ich habe kürzlich EclipseLink auf seine aktuelle, neueste Version 2.5.1 mit JPA 2.1 aktualisiert.

Lange Redewendung: Durch den Verweis auf eine verschachtelte Eigenschaft in einer Entität wie root.get("property1").get("propery2InAnotherRelatedEntity") wird immer eine überflüssige Verknüpfung generiert, die im Allgemeinen nicht passieren sollte. p>

Bitte vergib mir, wenn ich so viele Überarbeitungen gemacht habe, aber ich musste ...:)

    
Tiny 03.04.2014, 00:32
quelle

4 Antworten

1

Redundante Joins in Ihren Beispielen werden durch falsche JPA-Kriterienabfragekonstruktion und nicht durch das Vorhandensein von Unterabfragen in ihnen erzeugt. Der Titel der Frage hat also wirklich keinen Sinn.

Um redundante Joins loszuwerden, müssen Sie nur die Kriterien richtig konstruieren. Und tatsächlich ist die Kriterienabfrage in Ihrem EDIT 2 die korrekte Übersetzung Ihrer ursprünglichen SQL-Abfrage zu Beginn der Frage in die JPA-Kriteriensprache und sollte keine redundanten Joins erzeugen. Ihr Experimentieren mit Hibernate bestätigt es. Und die QueryException , die du bekommen hast, ist definitiv ein Fehler von EclipseLink. Ich schlage vor, dass Sie es den Entwicklern von EclipseLink melden: Ссылка .

Aber tatsächlich wird die Unterabfrage hier überhaupt nicht benötigt, und Joins sind normalerweise nicht böse, wenn sie richtig verwendet werden. Daher schlage ich vor, die SQL-Abfrage durch diese vollkommen äquivalente, aber prägnantere zu ersetzen:

%Vor%

Die Übersetzung in die Kriterienabfrage ist ebenfalls viel einfacher und klarer (und wird EclipseLink sicher nicht verwirren:)):

%Vor%

Und die Leistung in MySQL wird nicht schlechter sein als die des ursprünglichen.

    
dened 14.04.2014 10:24
quelle
1

Hat JPA native Methoden?
Ich weiß, Hibernate kann komplexe Abfrage durch native sql tun, so dass Sie eine Optimierung für die SQL machen können.

    
Eric Wang 16.04.2014 18:57
quelle
1

Könnte es so einfach sein:

%Vor%

Dabei ist country_name der Parameter, nach dem Sie suchen, und list die Liste der Objekte, die von der systemeigenen Abfrage zurückgegeben werden?

    
Ardi Goxhaj 17.04.2014 11:54
quelle
0

Dies ist nur eine unvollständige / unvollständige Antwort (ich hätte sie an die Frage anhängen können, aber es gibt bereits so viele Überarbeitungen).

Bezüglich EDIT 4 in der Frage ergibt die folgende Kriterienabfrage eine korrekte SQL-Abfrage (bezüglich EXISTS() ).

%Vor%

Dies erzeugt die folgende Abfrage.

%Vor%

Ich werde nicht meine eigene Antwort akzeptieren.

    
Tiny 14.04.2014 18:55
quelle