joinとeager_loadとpreloadの違い
対象者
・rails 1,2年目の弱小エンジニア
・N + 1問題にとりあえずincludeで対処している人
概要
railsのテーブル結合するメソッドに主に上記の3つがあります。
そいつらの使い分けを、初級者に分かりやすく説明しようと思います。
また後半では、preloadとeager_loadの処理の概要を説明しようとしてます。
結論
# こんな感じで使います
User.join(:articles).where(articles: {is_published: true})
User.preload(articles: :comments, :company).each do { |user| user.articles.title }
User.eager_load(articles: :comments :company).where(articles: {is_published: true})
No | メソッド | SQL | キャッシュ |
---|---|---|---|
1 | join | join | ✖︎ |
2 | preload | select | ○ |
3 | eager_load | left_join | ○ |
-
join
テーブルをくっつけるけど、キャッシュはしません。
その結果、絞り込みとかその場ではできるけど後で関連テーブルのデータを取ってこれません。
また、joinなのでarticleを持っていないUserは取れません。
これを利用して絞り込みとかにもよく使われます。 -
preload
テーブルをくっつけません。キャッシュはします。
クエリがテーブルの数発行されてテーブル結合されません。
あくまでselectで関連テーブルを1つづつ別々に取り出します。
なので、whereによる絞り込みができません -
eager_load
こいつが最強です。テーブルくっつけるし、キャッシュもします。
ただ、多対多のテーブル読み込むとめっちゃ重くなったりします。
preloadとeager_loadのイメージ
user10人がartcile10記事で各々に10個コメントがあるとしましょう。
つまり各テーブルのレコード数は以下のようになります。
user 10人
article 100件
comment 1000件
preload
連結されていないテーブルが複数読み込まれます。(テーブル数分の3回SQLが発行される)
つまり、テーブルの横幅が狭くなって比較的軽いです。
user(10レコード)
id | name | gender |
---|---|---|
1 | araki | male |
2 | yamato | male |
article(100レコード)
id | title | content | user_id |
---|---|---|---|
1 | 愛 | ホゲホゲ | |
2 | 睡眠 | フガフガ | 2 |
comment(1000レコード)
id | content | article_id |
---|---|---|
1 | 素晴らしい | |
2 | zzz | 1 |
eager_load
全てのテーブルを結合して、それを1000レコード分繰り返します。
めっちゃ重いけど、その代わり絞り込みとかはしやすいです。
user-articles-commentsの結合テーブル(1000レコード)
id | title | content | user_id | id | name | gender | id | content | article_id |
---|---|---|---|---|---|---|---|---|---|
1 | araki | male | 1 | 愛 | ホゲホゲ | 1 | 1 | 素晴らしい | |
2 | yamato | male | 2 | 睡眠 | フガフガ | 2 | 2 | zzz | 1 |
終わり
zenn初投稿でした。
稚拙な文章をここまで読んでいただきありがとうございます!
間違いなどがありましたら、ご指摘いただけるとありがたいです!
Discussion