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?
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.
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.
Technical note: joins in Rails runs an SQL 'inner join' operation and returns the records from the model you're operating on.
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!
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").
.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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With