Posted on: Written by: K-Sato
⚠️ This article was posted over a year go. The information might be outdated. ⚠️

Table of Contents

Joins

  • Uses LEFT INNER JOIN.
  • Is used to filter results(not accessing records from a relationship).
  • Dose not load data into memory. Thus, won’t stop N+1 queries.
Post.joins(:comments)
=>
Post Load (21.3ms)  SELECT  "posts".* FROM "posts" INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"

Preload

  • Loads the data in multiple queries.
  • You can’t use any condition like where with it.
Post.preload(:comments).map { |post| post.comments }
=>
Post Load (0.7ms)  SELECT "posts".* FROM "posts"
Comment Load (17.7ms)  SELECT "comments".* FROM "comments" WHERE "comments"."post_id" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)

With where clause

Post.preload(:comments).where("comments.id=1")
=>
ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "comments")

Eager_Load

  • Loads all associated data in single quer using LEFT OUTER JOIN.
Post.eager_load(:comments)
=>
SELECT  DISTINCT "posts"."id" FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" LIMIT $1  [["LIMIT", 11]]
SELECT "posts"."id" AS t0_r0, "posts"."title" AS t0_r1, "posts"."description" AS t0_r2, "posts"."user_id" AS t0_r3, "posts"."created_at" AS t0_r4, "posts"."updated_at" AS t0_r5, "posts"."status" AS t0_r6, "comments"."id" AS t1_r0, "comments"."content" AS t1_r1, "comments"."post_id" AS t1_r2, "comments"."created_at" AS t1_r3, "comments"."updated_at" AS t1_r4 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" WHERE "posts"."id" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)  [["id", 1], ["id", 2], ["id", 3], ["id", 4], ["id", 5], ["id", 6], ["id", 7], ["id", 8], ["id", 9], ["id", 10], ["id", 11]]

Includes

The includes method works like eager_load if you have a where or order clause that references a relationship. Otherwise, it works like preload.

Post.includes(:comments)
=>
Post Load (4.1ms)  SELECT  "posts".* FROM "posts" LIMIT $1  [["LIMIT", 11]]
Comment Load (0.5ms)  SELECT "comments".* FROM "comments" WHERE "comments"."post_id" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)

参考

About the author

I am a web-developer based somewhere on earth. I primarily code in TypeScript, Go and Ruby at work. React, RoR and Gin are my go-to Frameworks.