0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】joins/preload/eager_load

Posted at

はじめに

joins/preload/eager_loadについて調べた内容を整理します。

メソッドの比較

メソッド JOIN 子の条件で親を絞る N+1防止 発行されるSQL 用途
joins INNER JOIN できる × 1クエリ 条件付き検索
preload しない できない 2クエリ 関連のみ使用
eager_load LEFT OUTER JOIN できる 1クエリ 条件付き検索+ N+1防止

JOINの種類

種類 残るレコード マッチしない右側の扱い
INNER JOIN 両方にマッチする行のみ 除外される
LEFT OUTER JOIN 左側の全行 NULLで埋められる

joins

User.joins(:books).where(books: { title: "Ruby" })
発行されるSQL
SELECT "users".* FROM "users"
INNER JOIN "books" ON "books"."user_id" = "users"."id"
WHERE "books"."title" = 'Ruby'
  • 子テーブルbooksの条件で親テーブルusersのレコードを絞り込める
  • 関連するbooksは読み込まれていないため、user.booksを呼ぶとN+1問題が発生する
  • eager_load のようにLEFT OUTER JOINで全カラムを取得しないため、結果が軽く、重複行が発生しない

preload

User.preload(:books)
発行されるSQL
-- 親レコード(users)を取得
SELECT "users".* FROM "users";
-- 子レコード(books)を取得
SELECT "books".* FROM "books" WHERE "books"."user_id" IN (1, 2, 3, ...);
  • SQLが親テーブルと子テーブルの2回発行される
  • Railsが取得したusersとbooksをメモリ上で照合して user.booksを使えるようにする(N+1防止)
    • user.id == book.user_id を照合
    • 関連するBookをUserに紐づける
  • JOINをしないため、SQLが軽い
  • 関連は使えるが、条件は効かない
条件は使えない
User.preload(:books).where(books: { title: "Ruby入門" }) # 実行できない
User.preload(:books).order('books.title ASC') # 実行できない
関連は使える:user.booksはすでに読み込まれている
users.each do |user|
  user.books.each do |book|
    puts "#{user.name} - #{book.title}"
  end
end

eager_load

User.eager_load(:books).where(books: { title: "Ruby" })
発行されるSQL
SELECT "users"."id", ..., "books"."id", ..., "books"."title"
FROM "users"
LEFT OUTER JOIN "books" ON "books"."user_id" = "users"."id"
WHERE "books"."title" = 'Ruby'
  • LEFT OUTER JOINを使って、親と子を1クエリで取得する
  • 関連の条件やソートがSQLに反映される(N+1防止)
  • has_manyの関連の場合は親が重複する

includes

preloadeager_loadを自動で使い分ける

  • 判断基準
    • 関連に条件やソートがない -> preload
    • 関連のカラムにwhere や orderを使っている -> eager_load
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?