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?

[ActiveRecord] includesとpreload、eager_loadについて

0
Posted at

はじめに

ActiveRecordとは、Ruby on Railsに標準で組み込まれている ORM(Object-Relational Mapping)ライブラリ。SQL文を直接記述することなく、DB操作をRubyのオブジェクト操作に変換して簡単に実現できる。
includespreloadeager_loadどれもN+1問題を防ぐためのEager Loading(事前読み込み) です。「何がなに?」と思ったため、違いについてまとめていきます。

includes

includesメソッドは、条件によってpreloadeager_loadに自動で使い分けている。

preloadと同様

Ruby
User.includes(:posts)
SQL
SELECT * FROM users;
SELECT * FROM posts WHERE user_id IN (...);

JOINを使わず、関連テーブルごとに独立したクエリを投げている

eager_loadと同様

Ruby
User.includes(:posts).where(posts: { published: true })
SQL
SELECT * FROM users
LEFT OUTER JOIN posts ON ...
WHERE posts.published = true;

ActiveRecordが「JOIN必要そうだな」と判断すると自動で切り替えている

preloadはどこで使う?

preloadを使う時は、主に以下の二つ。
・ただ表示するだけ(一覧画面など)
・データ量が多いとき
)

Ruby
User.preload(posts: :comments)

段階的に3回クエリを投げる

usersを取得
SELECT "users".* FROM "users";
postsを取得
SELECT "posts".* FROM "posts"
WHERE "posts"."user_id" IN (1, 2, 3, ...);
commentsを取得
SELECT "comments".* FROM "comments"
WHERE "comments"."post_id" IN (10, 11, 12, ...);

流れ的には、
users取得 →(user.idを集める)→ posts取得 →(post.idを集める)→ comments取得

件数が多すぎると、メモリを多く消費するので注意!!

eager_loadはどこで使う?

・SQLを明示的にコントロールしたい
・クエリを1回にまとめたい

Ruby
User.eager_load(:posts).where(posts: { published: true })

JOINしていることを明確に示しているだけなので、

User.includes(:posts).where(posts: { published: true })

と同じ

参考記事

ActiveRecordのpreloadが親子関係をキャッシュする仕組みを調べてみた
似ているようで全然違う!?Activerecordにおけるincludesとjoinsの振る舞いまとめ
ActiveRecordのincludes、joins、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?