ActiveRecordでpluckの代わりにselectを使ってサブクエリ化する

こんにちは!kossyです!




さて、今回はActiveRecordのpluckではなくselectを使ってサブクエリを書いて、
一回のSQL発行でデータを取得する方法について、ブログに残してみたいと思います。




環境
Ruby 2.5.1
Rails 6.0.3.2
MacOS Catalina



サブクエリとは

「副問合せ」ともいい、SQL文の中に入れ子になって書かれたSQL文のことです。
サブクエリを用いることで、複雑な問合せが可能になったり、書き方によっては
余計なSQLの発行を防ぐことができます。

前提

・Userモデル(ユーザー)
・DailyReportモデル(日記)

user has_many daily_reports
daily_report belongs_to user

という関連が組まれていると想定

実験

pluckの場合

(条件が残念なのは勘弁してください、、、)
「日記テーブルの中で紐づくユーザーが昨日よりも最近作られたユーザーの日記を取得したい」という場合

pluckだとSQLが2回発行される

$ DailyReport.where(user_id: User.where('created_at > ?', Date.yesterday).pluck(:id))
   (0.6ms)  SELECT `users`.`id` FROM `users` WHERE (created_at > '2020-11-26') # 1回目
  DailyReport Load (0.7ms)  SELECT `daily_reports`.* FROM `daily_reports` WHERE `daily_reports`.`user_id` IN (9, 10, 11, 12) # 2回目

Selectの場合

1回の発行で取得できる

$ DailyReport.where(user_id: User.where('created_at > ?', Date.yesterday).select(:id))
  DailyReport Load (3.4ms)  SELECT `daily_reports`.* FROM `daily_reports` WHERE `daily_reports`.`user_id` IN (SELECT `users`.`id` FROM `users` WHERE (created_at > '2020-11-26'))


IN区の中でSELECT文を使って、1回のSQL発行で問合せを行っているのがわかります。
サブクエリを使って、パフォーマンスのいいアプリケーションを作りましょう!




勉強になりました。




参考にさせていただいたサイト
https://madogiwa0124.hatenablog.com/entry/2018/11/30/183412