Rails eager_load, joins and includes - when to use what
If you're developing a web application with Ruby on Rails, you may encounter slow queries as your database grows. To enhance performance, you can use eager loading, which lets you load related records upfront instead of separate queries for each record.
Eager loading
Eager loading is a method that permits you to retrieve associated records in a single query instead of multiple database queries. This can notably improve your application's performance by minimizing the number of database calls.
For instance, suppose you have a User
model with many projects. In that case, you can retrieve all the users and their related projects in one query using eager loading:
# LEFT OUTER JOIN - this means that all records from the primary table are returned, along with any associated records that match the specified conditions.
@users = User.eager_load(:projects).where("projects.published = ?", true)
This code will obtain all the users and their associated projects in a single query instead of a separate query for each user's projects. Apart from eager loading, Rails also provides other loading techniques that can optimize your queries.
Lazy loading
This approach loads associated records when they are needed rather than loading them upfront. This can be helpful when you have a large number of associations and don't want to load them all at once.
@user = User.find(1)
# Projects are loaded when called
@projects = @user.projects
Preloading
This technique is comparable to eager loading, but instead of joining the related records in a single query, it makes a separate query for each association. This can be useful when you need to modify the association's query or when the related records are not needed in every query.
# loads the association data in a separate query
@users = User.preload(:projects)
Includes vs. Joins
Both includes
and joins
can be used for eager loading, but they operate differently. Includes will load the associated records using separate queries, while joins will join the associated records into a single query. Both methods are very smart in Rails - they can create left outer join
automagically when needed.
# load associations separately from the main query - I don't want to load them all at once
@users = User.includes(:projects)
# I know that I will iterate projects per each user, so please prepare one sql query and give me the all results now
@users = User.joins(:projects)
So:
- use
includes
when you don't need the associated records in every query. Because it's smart enough to decide: If nowhere
clause references the included tables, it usespreload()
, if we havewhere
then it's switching toeager_load()
- and use
joins
when you do.
In conclusion, optimizing database queries is essential in building high-performance web applications. Eager loading, lazy loading, preloading, and other loading techniques can help you achieve this goal. By understanding these methods and when to apply them, you can enhance the performance of your Rails application.