LoginSignup
17
13

More than 5 years have passed since last update.

pluckの功罪(不要なDBアクセスを避けるために)

Posted at

Railsにある.pluckメソッドを使っていたところ、本来必要ないN+1クエリを発生させてしまいました。

pluckメソッドとは

ご存じの方も多いかもしれませんが、.pluckメソッドはActiveRecord::Relationwhereなどをかけていった結果のクラス)にあって、リレーションの条件で特定のカラムを取ってくる、というものです。

ぱっと聞けば、ふつうに.map(&:column)とするのとそんなに変わらないようにも思えます。

メリット

この.pluckのメリットは、「モデルの生成をせず、直接特定の列だけを取ってくるSQLを投げる」ということです。余計な列の取得やActiveRecordオブジェクトの生成をすっ飛ばして、値だけを取ってくることができます。

デメリット

ところが、この「ActiveRecordオブジェクトを介さない」 ということは、時としてデメリットに早変わりしてしまいます。というのも、モデル取得時にEager Loadをかけていた場合も、そちらには目もくれず、改めてSQLを投げてしまうのです。リレーションで複数オブジェクトを取得しているときに、各オブジェクトのhas_manyに対してpluckしてしまえば、あっという間にN+1クエリの発生です。

なんとかしてみる

pluckではeager loadを無視してしまう、mapでは不要な場合にも全列取得・ActiveRecord生成をしてしまう、と都合の合わない両者ですが、loaded?でロード状況を見れば、自動で都合の良いほうに切り替えることも可能です。

rel = SomeModel.some_scope(:arg)
rel.loaded? ? rel.map(&:column) : rel.pluck(:column)

.mapluckとでも名前を付けて、ActiveRecord::Relationに入れておいても便利かな、とちらっと思いました。

関連記事

17
13
1

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
17
13