includes,joins,eager_load,preloadの違いを噛み砕いて説明する

## はじめに
自分がRailsエンジニアとしてインターンをしており、その中で直近で一番意味わからんな。と思ったことがこれです。自分の学習のためにもしっかりとまとめました。他の記事よりなるべく初心者にもわかりやすくを意識して書きました。

*色々な人がこれについて記事を書いているので下の参考文献も合わせて確認ください。*
# そもそもこれどういう時使うの？
親子関係のtableにおいて親のものを呼び出す時に子のデータも一緒に呼び起こしてcontrollerの記述をスッキリできるものや、主にeach do文を使った時に発生する[N+1問題](https://qiita.com/shingo-nakanishi/items/c02808f76aa4c30271a3)を解決するためのものである。

ここではN+1問題の詳細については触れないが、ActiveRecordによるSQLの発行回数がめちゃくちゃ多くなってしまってえげつないことになるからとりあえず対処しなければならないものという認識で良い（？）。

でもこんなに種類があって、どれがどう優れていて、どう劣っているか。よくわからない時にこれを見て欲しい。
# includes
とりあえずN+1問題の時はこれで解決するイメージだが、実際にどのようなSQLが働いているかというと

```SQL
User.includes(:posts)

# =>
SELECT `users`.* FROM `users`
SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` IN (1, 2, 3, ...)

User.includes(:posts).where('posts.desc = "ruby is awesome"').to_a

# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
       "posts"."title" AS t1_r1,
       "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
WHERE (posts.desc = "ruby is awesome")
```
ざっくりいうと**preloadの上位互換**かつ**eager_loadとしても使える**。
## preloadはどこが劣っているか
`User.preload(:posts).where("posts.desc='ruby is awesome'")
`を使うことができない。がincludesではそれを使うことができる。
つまり**whereで絞り込みができるpreload**。
## どういった場合eager_loadとして使えるのか
先ほどのwhereを使った場合はeager_loadとして挙動する。(referencesする)
[LEFT OUTER JOIN](http://www.dofactory.com/sql/left-outer-join)の動きをする。

```SQL
User.includes(:posts).where(name: 'User 1').where(posts: {title: 'Post 1-1'})
  SQL (0.2ms)  SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "users"."author" AS t0_r2, "users"."created_at" AS t0_r3, "users"."updated_at" AS t0_r4, "posts"."id" AS t1_r0, "posts"."title" AS t1_r1, "posts"."created_at" AS t1_r2, "posts"."updated_at" AS t1_r3, "posts"."user_id" AS t1_r4 FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE "users"."name" = ? AND "posts"."title" = ?  [["name", "User 1"], ["title", "Post 1-1"]]
```
# eager_load
正直、includesの説明と被ってしまうと思うが、**includes+reference**の動きをする。
eager_loadは指定したアソシエーションをLEFT OUTER JOINで取得し、キャシュする。 
また、preloadとは違いは、指定したテーブルに対しての絞り込み（where）が行える。

```SQL
User.eager_load(:posts).to_a

# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
       "posts"."title" AS t1_r1, "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
```
# preload
上のincludesの説明を読んで欲しい。whereを使うことのできないincludes。
eager_loadと違って、**JOINしたくない大きいテーブルを扱うときはpreloadを使うのがいい**。

```SQL
User.preload(:posts).to_a

# =>
SELECT "users".* FROM "users"
SELECT "posts".* FROM "posts"  WHERE "posts"."user_id" IN (1)
```
# joins 
eager_load, preload との違いはキャッシュしない。（１度しかデータを使用しない）
joinsはinner joinを行うので、データは[inner join](https://qiita.com/akishin/items/36dba4b2ccdaefb53dc6)的に捨てられる。
つまり**データのしぼりこみ**に使える。

```SQL
User.joins(:posts).where(posts: { id: 1 })
# SELECT `users`.* FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id` WHERE `posts`.`id` = 1
```

# まとめ
これは[ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い](https://qiita.com/k0kubun/items/80c5a5494f53bb88dc58)に書かれていた文ですが、**そのテーブルとのJOINを禁止したいケースではpreloadを指定し、JOINしても問題なくてとりあえずeager loadingしたい場合はincludesを使い、必ずJOINしたい場合はeager_loadを使いましょう。**という文があります。
この通りだなと思ったのでここに貼らせていただきました。

# 参考にした文献
[ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い](https://qiita.com/k0kubun/items/80c5a5494f53bb88dc58)
[Preload, Eagerload, Includes and Joins]
(http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html)
[Making sense of ActiveRecord joins, includes, preload, and eager_load]
(http://blog.scoutapp.com/articles/2017/01/24/activerecord-includes-vs-joins-vs-preload-vs-eager_load-when-and-where)
[preload, eager_load, includes, references, and joins in Rails](http://blog.ifyouseewendy.com/blog/2015/11/11/preload-eager_load-includes-references-joins/)

参考にした記事を書いた方々に感謝です。状態としては色々な記事の情報をまとめて理解しやすい言葉で説明した形になっていますが、今後、もっと理解できるようになったら修正したいと思います。