こちらの記事。よく参考にしてます。
https://qiita.com/k0kubun/items/80c5a5494f53bb88dc58
ここで言っているキャッシュとは何か?
同記事の最後の表についてなんとなくふわっとした理解でした。
特にキャッシュする・しないについて。
それについてまとめました。
Rails modelって
そのmodelに定義されたリレーションに則ってデータを取得できます
class User < ApplicationRecord
has_many :invoices
...
というUserモデルがあったとして
user = User.first
invoice = user.invoices
というふうに取得できますね
その時、invoicesはどのタイミングで取得する(SQLが発行される)かというと
user.invoices
としたタイミングです
結合してみよう
先程のmodelを使って結合してみよう
joins
user = User.joins(:invoices).first
user.invoices
1行目のタイミングで
SELECT "users".* FROM "users" INNER JOIN "invoices" ON "invoices"."user_id" = "users"."id" ORDER BY "users"."id" ASC LIMIT $1
2行目で
SELECT "invoices".* FROM "invoices" WHERE "invoices"."user_id" = $1
のようなSQLが発行されました。
invoicesを検索するタイミングは変わってませんね。
なるほど、これがキャッシュされたかどうかってことか。
preload
user = User.preload(:invoices).first
user.invoices
includes
preload/eager_loadをいい感じに判断して使用してくれる
1行目の時点でinvoiceも検索しに行ってます
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
Invoice Load (0.3ms) SELECT "invoices".* FROM "invoices" WHERE "invoices"."user_id" = $1 [["user_id", 1]]
2行目では特にSQLは発行されていません。
キャッシュされてますね。
そして、SQLの結合は使わずに2回SELECTすることでuser.invoicesを取得してます。
eager_load
user = User.eager_load(:invoices).first
user.invoices
Usersに対してInvoicesをLEFT OUTER JOINで結合してました。
user.invoicesではキャッシュされてるので何も発行しません。
キャッシュしないということ
joinsメソッドでは、結合先のデータを必要としないが、INNER JOINで絞り込みをしたいときに使用する。
なので、
user = User.joins(:invoices).first
user.invoices
のようなコードは無駄があるということ。
includesとwhereで絞り込みとキャッシュを行うべき。
以上
という感じ