JPQL query braucht zu lange

Bitte aktiviere JavaScript!
Hey Leute,

ich hab ein Problem mit meinem JPQL query das sieht aktuell so aus:

SELECT DISTINCT report FROM Report report LEFT JOIN report.tags tag WHERE report.type = :type AND (report.fId = :fId0 ) AND (report.tags in :tags OR report.tags IS EMPTY) ORDER BY report.date DESC

Das filtern der tags ist kein Problem, sobald ich aber "report.tags IS EMPTY" hinzufüge wird mein query extrem langsam und dauert ca. 25 Sekudnen. Normal dauert die ganze abfrage ca. 40ms.

Hat jemand eine Idee ob da evtl. was falsch ist? und wenn nein was ich machen könnte?

Vielen Dank schon mal
 
Also wenn Du nur report.tags in :tags schreibst ist es schnell (Ich gehe mal davon aus in tags steht auch was drin) und wenn du is empty schreibst wird es langsam?

Ich kenne mich nicht wirklich aus mit JPQL aber wenn du einen LEFT JOIN ohne ON Klausel in anderen SQL DB's machst, dann joined er die ganze Tabelle zu jeder Zeile, was bedeutet, du bekommst count(tags) * count(report) Zeilen als Antwort, was in 99% der Fälle nicht gewollt ist. Wenn er dann diese viel zu große Anzahl mit dem WHERE filtern muss, könnte es schon langsam werden.

Gruß

Claus
 
@Thallius In JPQL sind die Beziehungen in den Entities gegeben, daher braucht es hier kein ON.

@imox mich wundert vielmehr, dass die Query überhaupt läuft, denn report.tags dürfte ja eine Collection sein und IN verlangt auf der linken Seite einen Pfad zu einem "Einzelwert". D. h. da sollte schon mal "tag IN :tags" stehen. Wenn das nichts bringt, dann zeig mal bitte das resultierende SQL.
 
@mihe7 ja du hast recht das stimmte nicht ganz sorry.

SELECT DISTINCT report FROM Report report LEFT JOIN report.tags tags WHERE report.type = :type AND (report.fId = :fId0 ) AND (report.tags in :tags) ORDER BY report.date DESC


Ich sehe auch gerade dass ich vorher das query für die tags quasi selber gebaut hatte was dann so aussieht:

SELECT DISTINCT report FROM Report report LEFT JOIN report.tags tag WHERE report.type = :type AND (report.fId = :fId0 ) AND (tag.id = :tag0 OR tag.id = :tag1 ) ORDER BY report.date DESC

Also mit ner for schleife über die tags und einfach einzeln hinzugefügt. Und dass ist jetzt erstaunlicherweise auch schneller als als wenn ich das mit (report.tags in :tags) mache.

Und ja richtig ist eine collection. Und das funktioniert auch. aber sobald ich dann das IS EMPTY hinzufüge:

SELECT DISTINCT report FROM Report report LEFT JOIN report.tags tag WHERE report.type = :type AND (report.fId = :fId0 ) AND (tag.id = :tag0 OR tag.id = :tag1 OR report.tags IS EMPTY) ORDER BY report.date DESC

wird es extrem langsam.



Grad noch mal geschaut. So funktionierts jetzt mit IN auch besser ;)

SELECT DISTINCT report FROM Report report LEFT JOIN report.tags tags WHERE report.type = :type AND (report.fId = :fId0 ) AND (tags IN :tags) ORDER BY report.date DESC

was komischerweise nicht funktioniert ist jetzt dass direkt die tags anspreche. also das hier:

SELECT DISTINCT report FROM Report report LEFT JOIN report.tags tags WHERE report.type = :type AND (report.fId = :fId0 ) AND (tags in :tags OR (tags IS EMPTY)) ORDER BY report.date DESC

Also "tags IS EMPTY" funktioniert nicht. was ich gerade nicht so ganz verstehe warum? vielleicht würde es dann auch schnell gehen wenn das klappt? Kommt halt eine exception mit syntax error

The collection-valued path 'tags IS EMPTY' must resolve to an association field.
 
Zuletzt bearbeitet:
aber tags ist doch die collection. deswegen funktioniert doch "tags in :tags" auch. und wenn ich report.tags schreibe dann wirds langsamer und wenn ich report.tags IS EMPTY schreibe wirds halt richtig langsam von 20-40ms hoch auf 10-25 sekunden.
 
Wer erstellt in so einem FW eigentlich dann die Tabellen und vor allem die Indizes? Ich finde das befremdend, dass da anscheinend irgendwelche DB Logik von dem FW erstellt wird und man selber gar nicht mehr weiß was seine DB eigentlich macht, bzw. wie Sie aufgebaut ist.

In meiner DB würde ich jetzt einfach einen Describe mache und wüßte wo das <Problem liegt. Gibts hier sowas nicht auch?
 
Wer erstellt in so einem FW eigentlich dann die Tabellen und vor allem die Indizes? Ich finde das befremdend, dass da anscheinend irgendwelche DB Logik von dem FW erstellt wird und man selber gar nicht mehr weiß was seine DB eigentlich macht, bzw. wie Sie aufgebaut ist.

In meiner DB würde ich jetzt einfach einen Describe mache und wüßte wo das <Problem liegt. Gibts hier sowas nicht auch?
Der Punkt ist, dass man in JPQL eben nicht mit Tabellen sondern mit Objekten arbeitet. Die Abbildung auf das DB-Schema kann man angeben und folgt ansonsten natürlich bestimmten Regeln. Das Describe kannst Du auf der DB natürlich nach wie vor machen. Die "Tabellen" in JPQL sind aber keine Tabellen sondern eben Entities. Für JPQL braucht es kein Describe, denn die Klassen und Attribute hat er ja im Quelltext schon gegeben.
 
Der Punkt ist, dass man in JPQL eben nicht mit Tabellen sondern mit Objekten arbeitet. Die Abbildung auf das DB-Schema kann man angeben und folgt ansonsten natürlich bestimmten Regeln. Das Describe kannst Du auf der DB natürlich nach wie vor machen. Die "Tabellen" in JPQL sind aber keine Tabellen sondern eben Entities. Für JPQL braucht es kein Describe, denn die Klassen und Attribute hat er ja im Quelltext schon gegeben.
Soweit ok, aber warum muss er dann beim query noch selber einen join machen? Das sollte Dochten auch automatisch funktioniere oder? Bzw. woher weiß man das man den join selber mache muss?
 
@mihe7 danke dir für die Erklärung :) Hast du noch eine Idee? bzw. wenn ich den join mache report.tags tags ist ja tags dann die collection wieso funktioniert "tags IN :tags" ? aber "tags IS EMPTY" nicht. "report.tags IN :tags" funktioniert ja auch genau so wie "tags IN :tags" und "report.tags IS EMPTY" funktioniert ja auch. und was mich wunder warum "tags IN :tags" schneller ist als "report.tags IN :tags". hoffe nicht ganz so verwirrden xD.

@Thallius Woher man das weiß? Naja das kannste in der doku nachlesen einfach nach JPQL googeln.
 
Soweit ok, aber warum muss er dann beim query noch selber einen join machen? Das sollte Dochten auch automatisch funktioniere oder?
Zum Beispiel: INNER JOIN vs LEFT JOIN. Es gibt auch noch FETCH JOINs, dann wird die zurückgegebene Collection beschränkt.

Bzw. woher weiß man das man den join selber mache muss?
Gehen wir mal von aus, dass Report eine Collection von Tag-Objekten enthält und jedes Tag einen Namen hat. Wenn Du mal von Java-Properties ausgehst, dann würde report.getTags() etwas wie Collection<Tag> liefern. Dann gibt aber report.getTags().getName() keinen Sinn, denn getName() würde sich auf die Collection und nicht auf das einzelne Tag-Objekte beziehen.

So verhält es sich eben in JPQL auch: report.tags ist die Collection als Ganzes und report.tags.name gibt es nicht. Um ein einzelnes Element einer Collection darzustellen wird eine Identifikationsvariable verwendet. Das fängt schon beim FROM an:

Bei "FROM Reports" bezeichnet Reports ja kein einzelnes Objekt sondern die komplette Collection. In der WHERE-Klausel willst Du aber auf Attribute eines einzelnen Objekts zugreifen, daher gibt es die ID-Variable: "FROM Reports r". Dabei stellt r nun ein Objekt der Collection dar und Dinge wie "r.name", "r.tags", "r.creator.name" geben Sinn.

Natürlich gibt es Abfragen, wo man sich auf eine Collection als Ganzes bezieht: IS EMPTY zum Beispiel. Hier wird eine Collection erwartet, also ist "report.tags" richtig.

Hast du noch eine Idee?
In Bezug worauf?

wenn ich den join mache report.tags tags ist ja tags dann die collection wieso funktioniert "tags IN :tags" ? aber "tags IS EMPTY" nicht. "report.tags IN :tags" funktioniert ja auch genau so wie "tags IN :tags" und "report.tags IS EMPTY" funktioniert ja auch. und was mich wunder warum "tags IN :tags" schneller ist als "report.tags IN :tags". hoffe nicht ganz so verwirrden xD.
Genau aus den oben genannten Gründen: tags ist ein Element der Collection report.tags und für dieses eine Element kann ich prüfen, ob es in einer "Menge" gegebener Elemente :tags enthalten ist (tags IN :tags). Umgekehrt funktioniert tags IS EMPTY nicht, weil tags keine Collection ist.

Zum Thema "report.tags IN :tags" funktioniert ja auch: nicht in Standard-JPQL.
 
na auf die eigentlich Frage ;) warum ist es so extrem langsamer wenn ich report.tags IS EMPTY hinzufüge. Bzw. hast du eine idee wie das eine normale Geschwindigkeit erlangt? Also darum gehts ja überhaupt ;) Die andern Fragen kamen von anderen usern.

ob es in einer "Menge" gegebener Elemente :tags enthalten ist (tags IN :tags).
hmmm ja logisch ^^ *facepalm* nur ein kleiner Denkfehler. Aber generell weiß ich das ja alles was wir hier besprechen und hab auch schon viele Dokus dazu gelesen. Aber hier komme ich gerade nicht weiter. Ich will halt ungern mir immer alle Objekte holen und das "filtern" in java machen. Wobei ich bezweifle dass das dann überhaupt schneller ist.
 
ups sorry. hmmm weiß grad gar nicht mehr wie ich mir das ausgeben kann? Ich benutze eclipselink. Weisst du wie?
 
In die persistence.xml:
XML:
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.logging.level.sql" value="FINE"/>
<property name="eclipselink.logging.parameters" value="true"/>
(letzte Zeile ist optional) aufnehmen.
 
mit IS EMPTY

SELECT DISTINCT t1.id AS a1, t1.date AS a2, t1.f_id AS a3, t1.type AS a4 FROM tbl_documentation_reports t1 LEFT OUTER JOIN (tbl_documentation_report_tags t2 JOIN tbl_documentation_tags t0 ON (t0.id = t2.f_tag)) ON (t2.f_report = t1.id) WHERE (((t1.type = ?) AND (t1.f_id = ?)) AND ((t0.id IN (?,?)) OR ((SELECT COUNT(t3.id) FROM tbl_documentation_report_tags t4, tbl_documentation_tags t3 WHERE ((t4.f_report = t1.id) AND (t3.id = t4.f_tag))) = ?))) ORDER BY t1.date DESC LIMIT ?, ?
bind => [DAILY, 741, 965230, 2790201, 0, 0, 10]



ohne IS EMPTY
SELECT DISTINCT t1.id AS a1, t1.date AS a2, t1.f_id AS a3, t1.type AS a4 FROM tbl_documentation_reports t1 LEFT OUTER JOIN (tbl_documentation_report_tags t2 JOIN tbl_documentation_tags t0 ON (t0.id = t2.f_tag)) ON (t2.f_report = t1.id) WHERE (((t1.type = ?) AND (t1.f_id = ?)) AND (t0.id IN (?,?))) ORDER BY t1.date DESC LIMIT ?, ?
bind => [DAILY, 741, 965230, 2790201, 0, 10]
 
@mihe7 Na logischerweise EclipseLink ;-) ?Dass hab ich doch nicht geschrieben ^^ anyway, was schlägst als Lösung vor?
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben