Skip to content

Instantly share code, notes, and snippets.

@luchiago
Created March 8, 2020 02:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luchiago/4acfa7a7241d24babd743b0a316662f4 to your computer and use it in GitHub Desktop.
Save luchiago/4acfa7a7241d24babd743b0a316662f4 to your computer and use it in GitHub Desktop.
Rails preload, eager_load and includes
# Example Models
class Tournament
attribute :name, :string
has_many :teams
end
class Teams
attribute :name, :string
attribute :position, :integer
attribute :points, :integer
belongs_to :tournament
end
# preload
=begin
Preload works generating two sql querys.
The first one is to load the model data, and the second one is to load the relationship and filter by the first model
If I want to use some filter, I should use the first model as filter, not the second one
=end
# Example of preload
Tournament.preload(:teams)
# SQL
SELECT "tournaments".* FROM "tournaments" # it will query everything (e.g. the name of tournament) of tournament
SELECT "teams".* FROM "teams" WHERE "teams"."tournament_id" IN (1)
# eager_load
=begin
eager_load uses a JOIN, specifically LEFT OUTER JOIN (or just LEFT JOIN),
which takes a join from the first table and the intersection with the second one
It forces one single query
=end
# Example of eager_load
Tournament.eager_load(:teams)
# SQL
SELECT "tournaments"."id" AS t0_r0, "tournaments"."name" AS t0_r1 \
FROM "tournaments" LEFT OUTER JOIN "teams" ON "teams"."tournament_id" = "tournaments"."id"
# includes
=begin
Very like the above methods, uses a single query
And accept a filter from the second table, not from the first one
=end
# Example of includes
Tournament.includes(:teams).where('team.position = 1')
#SQL
SELECT "tournaments"."id" AS t0_r0, "tournaments"."name" AS t0_r1, "teams"."id" AS t1_r0, \
"teams"."points" AS t1_r1, \
"teams"."position" AS t1_r2, \
"teams"."tournament_id" AS t1_r3
FROM "tournaments" LEFT OUTER JOIN "teams" ON "teams"."tournament_id" = "tournaments"."id"
WHERE (team.position = 1)
# Differences and when I should use each one
=begin
They are very similar. The difference relies what kind of query I want to do and about the perfomance
each method will have for that query. preload will fires two querys, but eager_load and includes not.
And if you want to know if you should use eager_load instead of includes, use includes first and see
the generated sql (with to_a) and the performance, if is too slow, use eager_load which always use one single query
even haves a "where"
=end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment