2016-08-23 2 views
0

Ich bin nicht in der Lage, das polymorphe Eltern einer Kindklasse eifrig zu laden. Die include-Anweisung scheint keinen Unterschied zu machen.ActiveJDBC eifrig laden von polymorphen Eltern

Kinderklasse:

@BelongsToPolymorphic(
    parents = {ParentRequest.class}, 
    typeLabels = {"parent_request"}) 
public class Child extends Model { 
} 

Geordnete Klasse:

public class ParentRequest extends Model { 

} 

Abfrage, die eifrig Kind + Eltern zurückkehren sollte:

List<Child> children = Child.where("... limit 500").include(ParentRequest.class); 

children.size(); //this gives me 500 
children.cachedParents.size(); //this gives me 0; 

Letztlich Ich versuche, die folgenden zu beschleunigen Betrieb:

Ich habe diese Operationen festgelegt, und die obige Operation scheint etwa 67 ms unabhängig davon zu dauern, ob .include (ParentRequest.class) für die Child.where() -Methode verwendet wird oder nicht.

Jeder Einblick oder Hilfe wird sehr geschätzt.

HINWEIS: Ich bin mir bewusst, dass das Kind nur ein Elternteil hat. In naher Zukunft wird es mehrere haben.

BEARBEITEN: Das Invertieren der Abfrage ergab aus einigen Gründen viel schnellere Ergebnisse. Das heißt, anstatt nach Children zu suchen und ParentRequest einzubeziehen, war die Operation viel schneller, wenn ich nach ParentRequest und Child suchte. Beachten Sie, dass ich in den Ergebnissen speziell eine findBySql-Anweisung verwendet habe, um die untergeordnete Tabelle mit der parent_request-Tabelle zu verknüpfen. Unten habe ich in den Details der Abfrage verlassen.

List<ParentRequest> parents = ParentRequest.findBySQL("SELECT child.*, parent_requests.* " + 
       "FROM child JOIN parent_requests ON child.parent_id=parent_requests.id WHERE " + 
       "RAND()<=? AND (child.metersToA BETWEEN ? AND ?) " + 
         " AND (child.metersToB BETWEEN ? AND ?) limit ?", 
       decimation_value, 
       minDistanceToA, maxDistanceToA , 
       minDistanceToB, maxDistanceToB, 
       MAX_POINTS).include(Child.class); 

Antwort

1

Ich schrieb einen einfachen Test und aktiviert Protokollierung:

Article article = Article.findById(1); 
article.add(Comment.create("author", "tjefferson", "content", "comment 1")); 
article.add(Comment.create("author", "tjefferson", "content", "comment 2")); 
LazyList<Comment> comments = Comment.where("author = ?", "tjefferson").include(Article.class); 

System.out.println(comments.size());// does loading of data, prints 2 
Article parent1 = comments.get(0).parent(Article.class); // does not generate DB query 
Article parent2 = comments.get(1).parent(Article.class); // does not generate DB query 

assert (parent1 == parent2); // true 

Ausführung dieses Codes wird Folgendes in einer Konsole anmelden:

SELECT * FROM comments WHERE author = ?", with parameters: <tjefferson>, took: 1 milliseconds 
SELECT * FROM articles WHERE id IN (?)", with parameters: <1>, took: 1 milliseconds 

Wie Sie sehen können , es gab nur zwei Abfragen an die Datenbank. Zusätzlich ist die Linie, die Sie erwähnen:

children.cachedParents.size(); //this gives me 0; 

wird nicht kompiliert, da ein LazyList das Mitglied nicht haben cachedParents.

Wenn Sie eine Schleife durch Kinder in diesem Fall und ein Elternteil wie:

child.parent(Parent.class) 

, es wird keine Datenbankabfragen in der Datenbank sein, da Objekte im Speicher zwischengespeichert werden.

Das Framework funktioniert wie erwartet. Der Grund für Ihr Timing ist das Gleiche mit und ohne include() s die Größe Ihres Datasets. 67 Millisekunden sind ziemlich schnell und der "Flaschenhals" ist überall.

Was Sie tun müssen, um einen Unterschied zu sehen, ist, einen viel größeren Datensatz zu laden.

Beachten Sie außerdem, dass je mehr Daten Sie laden, desto mehr Heap-Speicherplatz zugewiesen wird. Letztendlich löst die include() Methode das N + 1 Problem (http://javalite.io/lazy_and_eager), aber es bedeutet nicht, dass Ihre Anwendung schneller sein wird. Sie müssen experimentieren und entscheiden, ob es am besten ist, es für Ihre Fälle zu verwenden.

Zusammenfassung: Wenn Sie include() Methode verwenden, werden Sie weniger Aufrufe an die Datenbank haben, aber wird mehr RAM zuweisen. Es liegt an Ihnen zu entscheiden, ob es für Ihre App schneller ist.

+0

Vielen Dank für Ihre schnelle Antwort! Das Mitglied children.cachedParents.size kann ich im Debugger sehen, daher kann ich nicht erklären, warum ich es habe und nicht. Aus irgendeinem Grund fand ich, dass wenn ich die Suche invertiere, das ist eine Abfrage, die die beiden Tabellen verbindet, und dann ParentRequest mit einem Include (Child.class) herausziehen, bekomme ich viel bessere Leistung. Das Abfragen des obigen Weges dauerte ungefähr 25-35 Sekunden, um 500 Punkte zurückzugeben. Die Frage, wie ich in diesem Kommentar erwähne, erlaubte mir, 500 Punkte in 12-15 Sekunden oder weniger zurückzugeben. Ich werde meinen Psocode unten posten. –

+0

Ich bin froh zu sehen, dass das Framework wie erwartet funktioniert (ich bin mir sicher, dass 99 von 100 Fällen der Fall sind). Ich frage mich, was ich anders machen könnte. –

+0

Aktivieren Sie die Protokollierung: http://javalite.io/logging und sehen Sie, welche Abfragen in Ihrem Fall generiert werden. Danach können Sie diese manuell in der DB-Konsole ausführen, erklären und herausfinden, warum einige schneller und andere langsamer sind. ActiveJDBC ist nur ein Werkzeug - es gibt Ihnen Optionen :) – ipolevoy