2015-06-29 5 views
5

wenn ich nicht irre: joins bessere Leistung als includes weil auf Datenbankebene hat:Active Einsatz für die Leistung verbindet aber alle zugehörigen Datensätze in den Speicher geladen werden, wie mit umfasst

  • joins verursacht eine inner join
  • includes Ursachen ein subquery

Und in der Regel ist ein inner join schneller als ein subquery.

Beispiel:

#app/models/owner.rb 
class Owner < ActiveRecord::Base 
    has_many :pets 
end 

#app/models/pet.rb 
class Pet < ActiveRecord::Base 
    belongs_to :owner 
end 

Mit rails console:

# showing how 'includes' in rails causes an IN statement which is a subquery 
irb(main):001:0> @owners = Owner.all.includes(:pets) 
Owner Load (2.7ms) SELECT "owners".* FROM "owners" 
Pet Load (0.4ms) SELECT "pets".* FROM "pets" WHERE "pets"."owner_id" IN (1, 2, 3) 

Und jetzt mit joins was bewirkt, dass ein inner join:

irb(main):001:0> @owners = Owner.all.joins(:pets) 
Owner Load (0.3ms) SELECT "owners".* FROM "owners" INNER JOIN "pets" ON "pets"."owner_id" = "owners"."id" 

So würde es scheinen, wie es fast immer besser wäre, die Verwendung joins über includes weil:

  • includes eine subquery (die IN Anweisung) verursacht
  • joins verursacht eine inner join, die als eine Unterabfrage in der Regel schneller ist

Allerdings gibt es ein gotcha mit joins verwenden. This article does a great job describing it. Im Grunde lädt includes alle zugeordneten Objekte in den Speicher, so dass, wenn Sie für eines der Attribute für diese zugeordneten Objekte abfragen, es nicht die Datenbank trifft. In der Zwischenzeit lädt joins die Attribute der zugeordneten Objekte NICHT in den Speicher. Wenn Sie also nach einem der Attribute suchen, werden zusätzliche Treffer in der Datenbank ausgeführt.

Also hier ist meine Frage: Ist es möglich, innere Joins wie mit joins für die Leistung zu tun, aber gleichzeitig alle damit verbundenen Objekte in den Speicher wie includes10 laden?
Anders ausgedrückt: Ist es möglich, alle zugehörigen Objekte in den Speicher zu laden, wie includes tut, aber verursacht eine innere Verknüpfung im Gegensatz zu einer Unterabfrage?

Antwort

6

Ich denke, Ihre Annahme, dass eine JOIN ist immer schneller als zwei Abfragen ist nicht korrekt. Es hängt stark von der Größe Ihrer Datenbanktabellen ab.

Stellen Sie sich vor, Sie haben Tausende von Besitzern und Haustieren in Ihrer Datenbank. Dann musste Ihre Datenbank zuerst alle zusammenfügen, auch wenn Sie nur 10 Datensätze laden möchten. Auf der anderen Seite wäre eine Abfrage, die 10 Besitzer und eine Abfrage lädt, um alle Haustiere für diese 10 Besitzer zu laden, schneller als das JOIN.

Ich würde behaupten, dass beide Verfahren verschiedene Probleme zu lösen sind:

  • joins wird verwendet, wenn Sie zwei Tabellen zu kombinieren, benötigen Sie eine Abfrage auf den Daten der beiden Tabellen auszuführen.
  • includes wird verwendet, um N + 1 Abfragen zu vermeiden.

Btw: Die Rails documentation hat eine Notiz, dass includes Leistungsvorteile über joins hat:

Dies wird oft in einer Leistungsverbesserung gegenüber einem einfachen Join führen.

Verwandte Themen