Help us understand the problem. What is going on with this article?

pluckよりもmapのほうが高速なケース

More than 5 years have passed since last update.

ActiveRecord Relationから特定のカラムの配列を取得したいとき、基本的にはmapではなくpluckを使うべきです。

References

ただし、pluckはインスタンス化されたオブジェクトに対しても毎回SELECT文を投げてしまうようなので注意です。

pluckを使うべきケース

pluckは必要なカラムのみのSELECTに絞られているため、DB-アプリ間の消費帯域節約やカバリングインデックスが使えた場合などの観点でSQLパフォーマンスが有利です。
また、activerecordオブジェクトを生成せずに値を返すためインスタンス生成オーバーヘッドやメモリ消費の観点でも有利です。
DBから値をとってくる必要があるケースではpluckを使うべきです。

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

Benchmark

n = 2000
Benchmark.bm do |x|
  x.report { n.times { Profile.all.pluck(:id) } }
  x.report { n.times { Profile.all.map(&:id) } }
end
user system total real
pluck(:id) 2.030000 2.580000 4.610000 ( 7.576141)
map(&:id) 4.420000 2.850000 7.270000 ( 10.10201)

mapを使うべきケース

以下のように既にインスタンス化されたオブジェクトから値をぬきとりたい場合は、pluckだとかなり問題があります。
pluckの場合、毎回SELECT文が発行されてしまうので、ループで実行したりするとN+1問題みたいになります。
(ちなみに、eager_loadやincludeなどをかませてpluckでもSQL発行されない方法を探ってみましたがだめでした。ご存知のかたがいれば教えてください!)

一方mapの場合はメモリ内で計算するだけになりコストはほぼゼロです。

profiles = Profile.all
n = 2000
Benchmark.bm do |x|
  x.report { n.times { profiles.pluck(:id) } }
  x.report { n.times { profiles.map(&:id) } }
end
user system total real
pluck(:id) 2.020000 2.400000 4.420000 ( 7.245241)
map(&:id) 0.000000 0.000000 0.000000 ( 0.007601)

Environment

※ HostOSはMac OSXで、virtualboxのvagrant NFSモードでCentOS 6.5を起動してます
※ virtualboxだからかGuestOSでのディスクIOがかなり遅いのでたった2000件のテストですごい差が出ています
※ ベンチマークテストでのDBはsqlite3を使ってますが、mysqlでもほぼ同じ結果が出ることを確認しました

pry(main)> Rails.version
=> "4.1.6"
% uname -a
Linux *** 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
% cat /etc/issue
CentOS release 6.5 (Final)
Kernel \r on an \m
metheglin
敷布団カバーと掛布団カバーを逆につけて寝ています
https://metheglin.jp/#logical
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away