1
0

More than 3 years have passed since last update.

Rails modelのjoin戦略についての理解を深める1歩

Posted at

こちらの記事。よく参考にしてます。
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で絞り込みとキャッシュを行うべき。

以上

という感じ

1
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
1
0