2012-11-15 9 views
9

Sto cercando di ottimizzare le mie query sul mio sito.join profondamente nested in activerecord

ho 3 modelli, Foto, persona, Presenze

apparenze Foto has_many, e molte persone attraverso apparizioni tavolo Presenze solo ha un person_id, photo_id

Ora, se dovessi fare una ricerca su una 'persona' e volevo carico desiderosi loro apparenze e le foto, vorrei fare qualcosa di simile:

Person.joins(:appearances => :photo).limit(5) 

Ora, io non sono sicuro se questo è l'ideale, ma ipoteticamente la mia persona ha le apparenze che appartiene auna foto, che a sua volta ha apparenze e altre persone. Non so nemmeno se e come lo faresti in SQL vaniglia, ma sono curioso di sapere se è possibile.

Person.joins(:appearances => :photo => :appearaces => :person).limit(5) 

Questa sintassi si traduce in errori, ancora una volta, sono solo curioso, sto ricevendo la manipolazione le apparenze e le persone di una foto all'interno mio punto di vista, volevo solo fare esperimenti con i tempi di caricamento e vedere se questo è stato anche possibile.

risposta

11

Per "caricamento" si utilizza .include; .join è per l'esecuzione della funzionalità INNER JOIN. Sembra probabile che per il tuo caso utilizzerai entrambi (il join per ottenere la foto e l'include per ottenere le persone aggiuntive). Faccio questo punto perché il solo .join non eseguirà il caricamento ansioso (e quindi effettuerà le query in seguito quando si accede alle entità associate).

Se si desidera associazioni annidati ansioso-carico, è possibile utilizzare la sintassi descritta nel Ruby on Rails Guida alle http://guides.rubyonrails.org/active_record_querying.html#eager-loading-multiple-associations

Sarebbe qualcosa in questo senso lavorare?

Photo.joins(:appearances => :person).includes(:appearances => :person).limit(5) 

Oppure hai bisogno di iniziare con la persona?

Person.joins(:appearances => :photo).includes(:appearances => :photo => :appearaces => :person).limit(5) 

Inoltre, come un (piccolo) nota finale: avete ": le apparenze" scritto in modo errato nella vostra ultima riga di codice (che afferma ": appearaces"), che potrebbero causare problemi.

EDIT: Dopo alcune prove minore, sembra che nidificano le associazioni includere nella forma

a => b => c => b => a 

non funziona. Tuttavia, il seguente modulo:

a => [b => [c => [b => a]]] 

Anche se, ovviamente, non è altrettanto bello.

Significato, utilizzando il seguente codice:

Person.includes(:appearances => [:photo => [:appearances => :person]]).find(38)  

Il seguente SQL è stata generata:

Person Load (0.3ms) SELECT `persons`.* FROM `persons` WHERE `persons`.`id` = 38 LIMIT 1 
Appearance Load (0.3ms) SELECT `appearances`.* FROM `appearances` WHERE (`appearances`.person_id = 38) 
Photo Load (0.3ms) SELECT `photos`.* FROM `photos` WHERE (`photos`.`id` = 1904) 
Appearance Load (0.3ms) SELECT `appearances`.* FROM `appearances` WHERE (`appearances`.photo_id = 1904) 
Person Load (0.3ms) SELECT `persons`.* FROM `persons` WHERE (`persons`.`id` IN (38,346)) 

Desideroso di caricare le altre persone provenienti da tutte le foto che includono persona con id # 38

+0

inferno si, sei un ninja! – jdkealy

+0

buona chiamata per l'errore di battitura ... digitando dalla memoria e non si scrive ortograficamente. – jdkealy