Dies ist eher eine Frage "Warum funktionieren die Dinge so?" Als eine Frage "Ich weiß nicht, wie ich das machen soll" ...
Das Evangelium zum Abrufen zugehöriger Datensätze, von denen Sie wissen, dass Sie sie verwenden werden, lautet: Verwenden :include
Sie sie, weil Sie einen Join erhalten und eine ganze Reihe zusätzlicher Abfragen vermeiden:
Post.all(:include => :comments)
Wenn Sie sich jedoch die Protokolle ansehen, findet keine Verknüpfung statt:
Post Load (3.7ms) SELECT * FROM "posts"
Comment Load (0.2ms) SELECT "comments.*" FROM "comments"
WHERE ("comments".post_id IN (1,2,3,4))
ORDER BY created_at asc)
Es wird eine Verknüpfung verwendet, da alle Kommentare auf einmal abgerufen werden, aber es handelt sich immer noch nicht um eine Verknüpfung (was in der gesamten Dokumentation zu sagen scheint). Die einzige Möglichkeit, einen Join zu erhalten, besteht darin, :joins
Folgendes zu verwenden :include
:
Post.all(:joins => :comments)
Und die Protokolle zeigen:
Post Load (6.0ms) SELECT "posts".* FROM "posts"
INNER JOIN "comments" ON "posts".id = "comments".post_id
Vermisse ich etwas Ich habe eine App mit einem halben Dutzend Assoziationen und auf einem Bildschirm zeige ich Daten von allen an. Es scheint besser zu sein, eine verbundene Abfrage anstelle von 6 Personen zu haben. Ich weiß, dass es in Bezug auf die Leistung nicht immer besser ist, einen Join durchzuführen, als einzelne Abfragen (wenn Sie nach Zeitaufwand arbeiten, scheinen die beiden oben genannten einzelnen Abfragen schneller zu sein als der Join), aber schließlich alle Dokumente Ich habe gelesen, dass ich überrascht bin, dass es :include
nicht wie angekündigt funktioniert.
Vielleicht Rails ist bewusst , die Performance - Problem und kommen nicht außer in bestimmten Fällen?
quelle
includes
(für jeden, der dies liest)Antworten:
Es scheint, dass die
:include
Funktionalität mit Rails 2.1 geändert wurde. Rails wurde in allen Fällen für den Join verwendet, aus Leistungsgründen wurde er jedoch geändert, um unter bestimmten Umständen mehrere Abfragen zu verwenden. Dieser Blog-Beitrag von Fabio Akita enthält einige gute Informationen zur Änderung (siehe Abschnitt "Optimiertes eifriges Laden").quelle
.joins
wird nur die Tabellen verbinden und ausgewählte Felder zurückbringen. Wenn Sie Assoziationen für Joins-Abfrageergebnisse aufrufen, werden Datenbankabfragen erneut ausgelöst:includes
lädt eifrig die enthaltenen Assoziationen und fügt sie in den Speicher ein.:includes
Lädt alle enthaltenen Tabellenattribute. Wenn Sie Assoziationen für das Ergebnis der Include-Abfrage aufrufen, werden keine Abfragen ausgelöstquelle
Der Unterschied zwischen Joins und Include besteht darin, dass die Verwendung der include-Anweisung eine viel größere SQL-Abfrage generiert, die alle Attribute aus den anderen Tabellen in den Speicher lädt.
Wenn Sie beispielsweise eine Tabelle voller Kommentare haben und a: joins => users verwenden, um alle Benutzerinformationen für Sortierzwecke usw. abzurufen, funktioniert dies einwandfrei und dauert weniger als: include, aber Sie möchten anzeigen Der Kommentar zusammen mit dem Benutzernamen, der E-Mail-Adresse usw. Um die Informationen mithilfe von: joins abzurufen, müssen separate SQL-Abfragen für jeden Benutzer durchgeführt werden, den sie abrufen. Wenn Sie Folgendes verwenden: Diese Informationen sind einsatzbereit.
Tolles Beispiel:
http://railscasts.com/episodes/181-include-vs-joins
quelle
Ich habe kürzlich mehr über den Unterschied zwischen
:joins
und:includes
in Schienen gelesen . Hier ist eine Erklärung dessen, was ich verstanden habe (mit Beispielen :))Stellen Sie sich dieses Szenario vor:
Ein Benutzer hat viele Kommentare und ein Kommentar gehört einem Benutzer.
Das Benutzermodell weist die folgenden Attribute auf: Name (Zeichenfolge), Alter (Ganzzahl). Das Kommentarmodell weist die folgenden Attribute auf: Inhalt, Benutzer-ID. Für einen Kommentar kann eine Benutzer-ID null sein.
Tritt bei:
: joins führt einen inneren Join zwischen zwei Tabellen durch. Somit
wird holen , wo user_id (Kommentare Tabelle) alle Datensätze gleich user.id (Benutzer - Tabelle). Also wenn du es tust
Sie erhalten wie gezeigt ein leeres Array.
Außerdem lädt Joins die verknüpfte Tabelle nicht in den Speicher. Also wenn du es tust
Wie Sie sehen,
comment_1.user.age
wird im Hintergrund erneut eine Datenbankabfrage ausgelöst, um die Ergebnisse zu erhaltenBeinhaltet:
: include führt eine linke äußere Verknüpfung zwischen den beiden Tabellen durch. Somit
führt zu einer verknüpften Tabelle mit allen Datensätzen aus der Kommentartabelle. Also wenn du es tust
Es werden Datensätze abgerufen, bei denen comment.user_id wie gezeigt Null ist.
Außerdem werden beide Tabellen in den Speicher geladen. Also wenn du es tust
Wie Sie sehen können, lädt comment_1.user.age einfach das Ergebnis aus dem Speicher, ohne im Hintergrund eine Datenbankabfrage auszulösen.
quelle
Neben Leistungsüberlegungen gibt es auch einen funktionalen Unterschied. Wenn Sie Kommentaren beitreten, fragen Sie nach Posts mit Kommentaren - standardmäßig einem inneren Join. Wenn Sie Kommentare einfügen, fragen Sie nach allen Posts - einem Outer Join.
quelle
tl; dr
Ich kontrastiere sie auf zwei Arten:
Joins - Zur bedingten Auswahl von Datensätzen.
Includes - Bei Verwendung einer Zuordnung für jedes Mitglied einer Ergebnismenge.
Längere Version
Joins soll die aus der Datenbank stammende Ergebnismenge filtern. Sie verwenden es, um Set-Operationen für Ihre Tabelle auszuführen. Stellen Sie sich dies als eine where-Klausel vor, die die Mengenlehre durchführt.
Post.joins(:comments)
ist das gleiche wie
Post.where('id in (select post_id from comments)')
Wenn jedoch mehr als ein Kommentar vorhanden ist, erhalten Sie doppelte Beiträge mit den Verknüpfungen zurück. Aber jeder Beitrag wird ein Beitrag sein, der Kommentare enthält. Sie können dies mit folgenden Punkten korrigieren:
Im Vertrag stellt die
includes
Methode einfach sicher, dass beim Verweisen auf die Beziehung keine zusätzlichen Datenbankabfragen vorhanden sind (damit keine n + 1-Abfragen durchgeführt werden).Die Moral lautet: Verwenden
joins
Sie diese Option, wenn Sie bedingte Mengenoperationen ausführen möchten, und verwendenincludes
Sie sie, wenn Sie für jedes Mitglied einer Sammlung eine Beziehung verwenden möchten .quelle
distinct
bringt mich jedes Mal. Vielen Dank!.joins fungiert als Datenbankverknüpfung und verbindet zwei oder mehr Tabellen und ruft ausgewählte Daten aus dem Backend (Datenbank) ab.
.inklusive Arbeit als linker Join der Datenbank. Es hat alle Datensätze der linken Seite geladen, hat keine Relevanz für das Modell der rechten Seite. Es wird zum eifrigen Laden verwendet, da alle zugehörigen Objekte in den Speicher geladen werden. Wenn wir Assoziationen für das Ergebnis der Include-Abfrage aufrufen, wird keine Abfrage für die Datenbank ausgelöst. Es werden einfach Daten aus dem Speicher zurückgegeben, da bereits Daten in den Speicher geladen wurden.
quelle
'joins' wird nur zum Verknüpfen von Tabellen verwendet. Wenn Sie Assoziationen für Joins aufgerufen haben, wird die Abfrage erneut ausgelöst (dies bedeutet, dass viele Abfragen ausgelöst werden).
Die Gesamtzahl von SQL beträgt in diesem Fall 11
Aber mit 'Includes' werden die enthaltenen Assoziationen eifrig geladen und in den Speicher eingefügt (alle Assoziationen beim ersten Laden laden) und die Abfrage nicht erneut ausgelöst
Wenn Sie Datensätze mit Includes wie @ records = User.includes (: organisations) .where ("organisations.user_id = 1") erhalten, wird die Abfrage ausgeführt
@ records.map {| u | u.organisation.name} Es wird keine Abfrage ausgelöst
quelle