2015-06-29 17 views
5

se non erro: joins ha prestazioni migliori rispetto includes perché a livello di database:uso ActiveRecord si unisce per le prestazioni, ma caricare tutti i record associati nella memoria come con include

  • joins provoca un inner join
  • includes cause un subquery

E, in generale, un inner join è più veloce di un subquery.

Esempio:

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

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

Utilizzando 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) 

E ora utilizzando joins che causa un 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" 

così sembrerebbe come sarebbe essere quasi sempre meglio l'uso joins su includes perché:

  • includes provoca una (la dichiarazione IN) subquery
  • joins causa un inner join che di solito è più veloce di un sottoquery

Tuttavia, v'è una Gotcha con l'utilizzo di joins. This article does a great job describing it. Fondamentalmente, includes carica tutti gli oggetti associati in memoria, in modo che se si esegue una query per uno qualsiasi degli attributi per tali oggetti associati, questo non colpisce il database. Nel frattempo, joins NON carica in memoria gli attributi degli oggetti associati, quindi se si esegue una query per uno qualsiasi degli attributi, effettua ulteriori hit sul database.

Quindi, ecco la mia domanda: è possibile eseguire join interni come con joins per prestazioni ma allo stesso tempo caricare tutti gli oggetti associati in memoria come fa includes?
In un altro modo: è possibile caricare tutti gli oggetti associati in memoria come fa includes, ma provoca un inner join in contrapposizione a un subquery?

risposta

6

Penso che la tua ipotesi che uno JOIN sia sempre più veloce di due query non è corretta. Dipende molto dalle dimensioni delle tabelle del database.

Immagina di avere migliaia di proprietari e animali domestici nel tuo database. Quindi il tuo database ha dovuto unirsi a tutti insieme prima, anche se vuoi solo caricare 10 record. D'altra parte una query che carica 10 proprietari e una query per caricare tutti gli animali domestici per quei 10 proprietari sarebbe più veloce di quella JOIN.

Direi che entrambi i metodi esistono per risolvere i problemi differenti:

  • joins viene utilizzato quando è necessario combinare due tabelle per eseguire una query sui dati di entrambe le tabelle.
  • includes viene utilizzato per evitare le query N + 1.

Btw: Il Rails documentation ha una nota che includes ha vantaggi prestazionali oltre joins:

Questo spesso risultare in un miglioramento delle prestazioni nel corso di un semplice aderire.

Problemi correlati