7

I get the benefits of using eager loading to avoid N+1 when fetching an array of objects with their associated records, but is it important to use eager loading when fetching a single record?

In my case

user has_many :addresses
user has_many :skills
user has_many :devices
user has_many :authentications

In the show action, I am trying to see with rack mini profiler if it is interesting to use eager loading

User.includes(:skills, :addresses, :devices, :authentications).find(params[:id])

But I seem to have the same number of sql requests..

Any advice on using eager loading for such case or not?

stefano_cdn
  • 1,362
  • 2
  • 15
  • 29

2 Answers2

14

is it important to use eager loading when fetching a single record?

For associations one level deep, no.

If you have nested associations, yes.

# class User
has_many :skills

# class Skill
belongs_to :category

# this code will fire N + 1 queries for skill->category
user.skills.each do |skill|
  puts skill.category
end

In this case, it is better to eager load skills: :category

User.includes(skills: :category).find(id)

Edit

Rails provide two ways to avoid N+1 queries, which it refers to as preloading and eager_loading.

Preload fires individual SQL queries for each collection.

Eager load attempts to construct one massive left-joined SELECT to retrieve all collections in 1 query.

The short version is that includes lets Rails pick which one to use. But you can force one way or the other.

User.eager_load(:skills, :addresses, :devices, :authentications).find(params[:id])

Should retrieve all records in 1 query.

Further reading:

Community
  • 1
  • 1
messanjah
  • 8,977
  • 4
  • 27
  • 40
4

Try using the Bullet gem for detecting unused or missing eager loading. It's designed to tell you if there are wasted include statements, or inefficient N+1 queries, where includes would help.

If there's a problem, it can be configured to output to the Rails logger to let you know. Or you can have it show you a notification in the browser on pages that need optimising.

Matt Gibson
  • 14,616
  • 7
  • 47
  • 79