Eager loading loads the full objects tree that is the associated records of the objects.
Consider we have two models Post and Comment and we have relation like post has many comments.
Post model has the relation has_many :comments
Comment model has the relation belongs_to :post
Now lets find all the posts and its comments and print the post text and comment text.
[source=ruby]
posts = Post.all(:limit => 20)
[/source]
Next we will iterate through all the post and and then get the comments for that post and print the post and comment text.
[source=ruby]
posts.each do |post|
puts post.post_text
post.comments.each do | comment |
puts comment.comment_text
end
end
[/source]
Okay this code works fine, nothing wrong but there is performance issue in this code, it fires 1 query to find all the post and N queries to find the comments for the post.
Lets try to measure the time taken to execute this code using Ruby Benchmark.
[source=ruby]
require ‘benchmark’
lazy loading = Benchmark.measure do
posts = Post.all(:limit => 20)
posts.each do |post|
puts post.post_text
post.comments.each do | comment |
puts comment
end
end
end.total
[/source]
[source=ruby]
puts lazy loading #
[/source]
Lets try to optimize the performance by trying some ways.
We can use the includes method provided by Active Record that loads the full objects tree that is the associated records of the objects.
[source=ruby]
posts = Post.includes(:comments).limit(20)
posts.each do |post|
puts post.post_text
post.comments.each do | comment |
puts comment.comment_text
end
end
[/source]
The above code fire 2 queries, one to find all the posts and the other to find the comments for the posts.
This concept is called eager loading, so the posts variable contains all the posts and the associated comments.
Lets try to measure the time taken to execute this code using Ruby Benchmark.
[source=ruby]
require ‘benchmark’
eager_loading = Benchmark.measure do
posts = Post.includes(:comments).limit(20)
posts.each do |post|
puts post.post_text
post.comments.each do | comment |
puts comment.comment_text
end
end
end.total
puts eager_loading #
[/source]
The time taken in eager loading is very less compared to lazy loading, so it is good to go with eager loading when we show associations data.