2016-06-29 24 views
1

Mit den folgenden CriteriaBuilder liefert Ergebnisse innerhalb von 1 Sekunde, wenn ich eine Karte von 1 oder 2 Einträge haben, aber wenn es 3 erreicht die Leistung der Abfrage fällt. Wenn dann ein vierter Eintrag hinzugefügt wird, wird die Leistung sogar noch mehr reduziert, bis zu dem Punkt, an dem ich sie nicht mehr gesehen habe.Warum sinkt die Abfrageleistung drastisch?

Ich habe versucht, stattdessen Sub-Abfragen zu verwenden, aber es scheint auf ein ähnliches Problem zu stoßen, wo 2 EXISTS-Unterabfragen Daten innerhalb einer angemessenen Zeit zurückgeben, aber 3 oder mehr werden zu einem großen Leistungseinbruch führen.

Ich habe festgestellt, dass ohne die ORDER BY die Abfrage funktioniert auch mit 3 Einträge (1 Sekunde oder weniger), aber sobald ich es wieder auf die gleichen 3 Einträge hinzufügen Suche dauert über 30 Sekunden. Hier

ist der Erbauer:

CriteriaBuilder builder = em.getCriteriaBuilder(); 
CriteriaQuery<Study> q = builder.createQuery(Study.class); 
Root<Study> rootStudy = q.from(Study.class); 

List<Predicate> pList = new ArrayList<Predicate>(searchMap.size()); 
q.select(rootStudy); 

Join<Study, Demographics> dem = rootStudy.join("demographics"); 
Join<Study, MetaData> met = rootStudy.join("metadata"); 

// add all conditions 
for (Map.Entry<XmlTagHashKey, String> entry : searchMap.entrySet()) { 

    MapJoin< Demographics, XmlTagHashKey, Field2 > mapJoin = demJoin.joinMap("fields"); 

    Path<String> attributePath = mapJoin.get("value"); 
    Predicate p = builder.and(builder.equal(mapJoin.key(), entry.getKey()), 
          builder.like(attributePath, "%" + entry.getValue() + "%")); 

    pList.add(p); 
} 

q.where(pList.toArray(new Predicate[]{})); 
q.orderBy(builder.desc( met.<String>get(XMLTagEnum.bbrad_status_updated.name()))); 

TypedQuery<Study> typedQuery = em.createQuery(q); 
typedQuery.setMaxResults(100); 
return getResultsList(typedQuery); 

Hier ist die SQL, die aus dem oben Builder erstellt wird, wenn ich 3 Map-Einträge:

SELECT t1.id, 
     t1.study_id, 
     t1.demographics_id, 
     t1.metadata_id 
FROM demographics_has_fields t8, 
     field t7, 
     demographics_has_fields t6, 
     field t5, 
     demographics_has_fields t4, 
     field t3, 
     demographics t2, 
     study t1, 
     metadata t0 
WHERE (((((t6.xmltag = ?) 
       AND t5.value LIKE ?) 
      AND ((t4.xmltag = ?) 
        AND t3.value LIKE ?)) 
      AND ((t8.xmltag = ?) 
       AND t7.value LIKE ?)) 
     AND (((((t2.id = t1.demographics_id) 
        AND ((t6.demographics_id = t2.id) 
          AND (t5.id = t6.field_id))) 
        AND ((t4.demographics_id = t2.id) 
         AND (t3.id = t4.field_id))) 
       AND ((t8.demographics_id = t2.id) 
         AND (t7.id = t8.field_id))) 
       AND (t0.id = t1.metadata_id))) 
ORDER BY t0.bbradstatusupdated DESC 

Hier ist ein Beispiel der Tabellenstruktur:

Table Structure

Was ich aCH versuche IEVE ist eine Studie aus, in dem der Wert eines Feldes ‚james‘ enthält und der XML-Tag wäre ‚1‘ (1 Name, 2 Geschlecht). Der Grund, warum ich eine Karte verwende, ist, dass Sie vielleicht auch nach zusätzlichen Feldern suchen möchten, zum Beispiel nach Geschlecht. Ich denke, der einzige Weg, das zu funktionieren, wäre mit bestehenden Sub-Abfragen oder Joins, wie ich oben getan habe.

Leider ist diese Datenstruktur ziemlich schlecht, aber wurde aus einer früheren Datenbank-Design geerbt, so bin ich ein bisschen mit ihm stecken.

+0

Hallo, hier ist ein toller Artikel über die Leistung der Abfrage zu kartieren, vielleicht wird es Ihnen helfen http://www.javaworld.com/article/2076240/build-ci-sdlc/optimize-a-query-on-a -map.html – Hrabosch

+0

Das muss super langsam sein. Wenn Sie Ihre Tabellenstrukturen, Beispieldaten und die erwartete Ausgabe hinzufügen, können wir Ihnen helfen, eine gut funktionierende Abfrage zu finden. –

Antwort

2

Wenn ich richtig verstehe, was Sie tun, dann fügen Sie Joins zu der Abfrage für jeden Map-Eintrag hinzu. Dies bedeutet, dass Sie die Menge der Daten, die die Abfrage verarbeiten muss, mit einer großen Anzahl für jedes Kartenelement multiplizieren. Dies führt zwangsläufig zu einer schlechten Skalierbarkeit.

Um zu überprüfen, ob dies wirklich das Problem ist, wie folgt vorgehen:

Führen Sie die (SQL) Anweisungen für 2 und drei Map-Einträge für die Datenbank und ihre Leistung messen. Stellen Sie sicher, dass Sie alle Einträge abrufen, nicht nur die ersten.

Wenn meine Vermutung richtig ist, können Sie mehr oder weniger den gleichen Leistungsabfall, sehen so ist dies kein JPA/Eclipse-Link Problem.

könnte die Lösung zu einem anderen Datenmodell zu wechseln, möglicherweise ein Stern-Schema. Aber das wird viele Dinge in Ihrer Anwendung beeinflussen und wir wissen zu wenig darüber.

+0

Sie haben 100% Recht, und ich vermutete so viel in Bezug auf das Multiplikationsproblem. Ich habe eine Tabelle Struktur Beispiel und einige Beispieldaten enthalten, lassen Sie mich wissen, wenn mehr Informationen benötigt werden! – james4563