pluckとmapの違い

そもそもCar.find(12)と実行された時、以下のようなことが起こっている。

  • 与えられたオプションを同等のSQLクエリに変換
  • SQLクエリを発行し、該当する結果をデータベースから取り出す
  • 得られた結果を行ごとに同等のRubyオブジェクトとしてインスタンス化する
  • 指定されていれば、after_findを実行し、続いてafter_initializeコールバックを実行する

データ取得と同時にARインスタンスにしている。ここでメモリを消費することになる。 where、all、findでも、単数だろうが複数だろうが、それ自体ではARインスタンスを生成してることでメモリを使い、それが増えれば増えるほどパフォーマンスに影響が出る。

pluck

pluckとmapをそれぞれ実行すると、結果は同じでもプロセスに違いがある。

Profile.all.pluck(:id)
  # => SELECT "profiles"."id" FROM "profiles"

Profile.all.map(&:id)
  # =>  Profile Load (11.8ms)  SELECT "profiles".* FROM "profiles"

pluckはSQL文を発行して、ここではidカラムのデータを取得するだけだが、mapは全てのカラムにアクセスしており、「Profile Load」とあり、ここでARインスタンスを生成している。pluckは必要なカラムのデータのみ取得する。また、ARインスタンスを生成しない。ゆえにDBにアクセスして、必要なカラムのデータだけほしい場合、pluckが良い。

map

一方、mapはすでに生成されたインスタンスから値を抜き取る場合に使う。「ticket = Ticket.last」のように変数に入ると、インスタンスになる。この時はmapがようそう。pluckでは毎回、クエリを発行してしまうので、N + 1の原因となる(ただし、近年のpluckはDBのアクセスを検知するとクエリを発行しないらしい)。

結論