Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails :include vs. :joins

This is more of a "why do things work this way" question rather than a "I don't know how to do this" question...

So the gospel on pulling associated records that you know you're going to use is to use :include because you'll get a join and avoid a whole bunch of extra queries:

Post.all(:include => :comments) 

However when you look at the logs, there's no join happening:

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)  

It is taking a shortcut because it pulls all of the comments at once, but it's still not a join (which is what all the documentation seems to say). The only way I can get a join is to use :joins instead of :include:

Post.all(:joins => :comments) 

And the logs show:

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

Am I missing something? I have an app with half a dozen associations and on one screen I display data from all of them. Seems like it would be better to have one join-ed query instead of 6 individuals. I know that performance-wise it's not always better to do a join rather than individual queries (in fact if you're going by time spent, it looks like the two individual queries above are faster than the join), but after all the docs I've been reading I'm surprised to see :include not working as advertised.

Maybe Rails is cognizant of the performance issue and doesn't join except in certain cases?

like image 268
Rob Cameron Avatar asked Jul 30 '09 19:07

Rob Cameron


People also ask

What is difference between include and join in Rails?

Includes uses eager loading whereas joins uses lazy loading. Both are used when certain operations are meant to be performed on associated tables. And here comes the difference.

What does include do in Rails?

Making queries ⚡️ with :includes Rails provides an ActiveRecord method called :includes which loads associated records in advance and limits the number of SQL queries made to the database. This technique is known as "eager loading" and in many cases will improve performance by a significant amount.

What does joins do Rails?

Technical note: joins in Rails runs an SQL 'inner join' operation and returns the records from the model you're operating on.

What is eager loading Rails?

Eager loading lets you preload the associated data (authors) for all the posts from the database, improves the overall performance by reducing the number of queries, and provides you with the data that you want to display in your views, but the only catch here is which one to use. Gotcha!


2 Answers

It appears that the :include functionality was changed with Rails 2.1. Rails used to do the join in all cases, but for performance reasons it was changed to use multiple queries in some circumstances. This blog post by Fabio Akita has some good information on the change (see the section entitled "Optimized Eager Loading").

like image 84
Greg Campbell Avatar answered Oct 21 '22 07:10

Greg Campbell


.joins will just joins the tables and brings selected fields in return. if you call associations on joins query result, it will fire database queries again

:includes will eager load the included associations and add them in memory. :includes loads all the included tables attributes. If you call associations on include query result, it will not fire any queries

like image 39
Prem Avatar answered Oct 21 '22 05:10

Prem