Rieles: incluir frente a: unir

Resuelto Rob Cameron asked hace 15 años • 8 respuestas

Esta es más una pregunta de "por qué las cosas funcionan de esta manera" que una pregunta de "No sé cómo hacer esto"...

Entonces, la mejor manera de extraer registros asociados que sabes que vas a usar es usarlos :includeporque obtendrás una unión y evitarás un montón de consultas adicionales:

Post.all(:include => :comments)

Sin embargo, cuando miras los registros, no se produce ninguna unión:

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) 

Está tomando un atajo porque extrae todos los comentarios a la vez, pero todavía no es una unión (que es lo que parece decir toda la documentación). La única forma en que puedo unirme es usar :joinsen lugar de :include:

Post.all(:joins => :comments)

Y los registros muestran:

Post Load (6.0ms)  SELECT "posts".* FROM "posts" 
                   INNER JOIN "comments" ON "posts".id = "comments".post_id

¿Me estoy perdiendo de algo? Tengo una aplicación con media docena de asociaciones y en una pantalla muestro datos de todas ellas. Parece que sería mejor tener una consulta unida en lugar de 6 personas. Sé que en términos de rendimiento no siempre es mejor realizar una unión en lugar de consultas individuales (de hecho, si nos fijamos en el tiempo invertido, parece que las dos consultas individuales anteriores son más rápidas que la unión), pero después de todos los documentos He estado leyendo y me sorprende ver que :includeno funciona como se anuncia.

¿Quizás Rails es consciente del problema de rendimiento y no se une excepto en ciertos casos?

Rob Cameron avatar Jul 31 '09 02:07 Rob Cameron
Aceptado

Parece que la :includefuncionalidad se cambió con Rails 2.1. Rails solía realizar la unión en todos los casos, pero por razones de rendimiento se cambió para usar múltiples consultas en algunas circunstancias. Esta publicación de blog de Fabio Akita tiene buena información sobre el cambio (consulte la sección titulada "Carga ansiosa optimizada").

Greg Campbell avatar Jul 30 '2009 19:07 Greg Campbell

.joinssimplemente unirá las tablas y traerá los campos seleccionados a cambio. si llama a asociaciones en el resultado de la consulta de uniones, se activarán consultas de la base de datos nuevamente

:includescargará ansiosamente las asociaciones incluidas y las agregará a la memoria. :includescarga todos los atributos de las tablas incluidas. Si llama a asociaciones sobre el resultado de la consulta de inclusión, no se activará ninguna consulta.

Prem avatar Apr 12 '2012 18:04 Prem

La diferencia entre uniones e inclusión es que el uso de la declaración de inclusión genera una consulta SQL mucho más grande que carga en la memoria todos los atributos de las otras tablas.

Por ejemplo, si tiene una tabla llena de comentarios y utiliza :joins => usuarios para obtener toda la información del usuario con fines de clasificación, etc., funcionará bien y tomará menos tiempo que :include, pero diga que desea mostrar el comentario junto con el nombre del usuario, correo electrónico, etc. Para obtener la información usando :joins, tendrá que realizar consultas SQL separadas para cada usuario que obtenga, mientras que si usó :include esta información está lista para usar.

Gran ejemplo:

http://railscasts.com/episodes/181-include-vs-joins

holden avatar Sep 29 '2009 09:09 holden