2012-08-14 14 views

risposta

47

Rails ha 2 modi per evitare il problema n + 1. Uno consiste nella creazione di una query basata su un grande join per inserire le associazioni, l'altra consiste nel creare una query separata per associazione.

Quando si eseguono le rotaie includes, quale strategia utilizzare per l'utente. Il valore predefinito è l'approccio di query separato (preloading) a meno che non pensi di utilizzare le colonne delle associazioni nelle tue condizioni o ordine. Dal momento che funziona solo con l'approccio joins, utilizza quello invece.

L'euristica delle rotaie a volte sbaglia o si può avere una ragione specifica per preferire un approccio all'altro. preload (e il relativo metodo companion eager_load) consentono di specificare la strategia da utilizzare per le rotaie.

+0

Impressionante - un angolo oscuro e non documentato di ActiveRecord quello. Grazie per aver brillato un po 'di luce! – Phantomwhale

+3

Questo blog discute lo stesso argomento http: //blog.bigbinary.it/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html –

+2

Questo post del blog è molto utile e chiaro http://blog.arkency.com/2013/12/rails4- precarico / –

-3

Come diceva apidoc "Questo metodo è obsoleto o spostato sull'ultima versione stabile. L'ultima versione esistente (v3.0.9) è mostrata qui." Quindi la differenza è che include solo NON deprecato.

+3

"deprecato o spostato". In questo caso viene spostato, non deprecato. E non sono la stessa cosa. –

+0

Scusa, ma se ho la possibilità di chiamarlo (Rails 3.2.6) non viene spostato per me, solo deprecato. – freeze

+2

l'apidoc viene enormemente confuso quando le persone rifattorizzano il codice da un modulo a un altro - può pensare che un metodo si sia spostato anche dal punto di vista dell'API pubblico che non ha –

0

Per la comprensione dettagliata consultare il blog this.

In bicchierini:

precarico carica i dati associazione in una query separata.

User.preload(:posts).to_a 

# => SELECT "users".* FROM "users" SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1) 

Include carica i dati di associazione in una query separata, proprio come precarico. Tuttavia è più intelligente rispetto a preload. Ma in alcuni casi combina le query.

Come include è più intelligente?

noi non è possibile utilizzare la tabella postale in cui condizione. La seguente query genererà un errore.

User.preload(:posts).where("posts.desc='ruby is awesome'") 

# => 
SQLite3::SQLException: no such column: posts.desc: 
SELECT "users".* FROM "users" WHERE (posts.desc='ruby is awesome') 

Ma noi possiamo usare tabella postale di cui interrogazione con includono

User.includes(:posts).where('posts.desc = "ruby is awesome"').to_a 

# => 
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0, 
     "posts"."title" AS t1_r1, 
     "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3 
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id" 
WHERE (posts.desc = "ruby is awesome") 

Come si può vedere include interruttori di utilizzare due query separate per la creazione di un unico SINISTRA Join esterno per ottenere il dati. E ha applicato anche la condizione fornita.

Problemi correlati