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のアクセスを検知するとクエリを発行しないらしい)。