pluck と map はどちらを使うべきなのか?
Userモデルの全レコードを取得して、idの配列を作成した時で試してみる
require 'bebnchmark'
Benchmark.bm 10 do |r|
r.report "pluck" do
User.all.pluck(:id)
end
r.report "map" do
User.all.map(&:id)
end
end
結果としてはこんな感じ
user system total real
pluck 0.003826 0.000972 0.004798 ( 0.013440)
map 0.022315 0.002486 0.024801 ( 0.070383)
mapの方がだいぶ長い。。。SQL的には何が違うんだろ
# pluck
SELECT `users`.`id` FROM `games`
# map
SELECT `users`.* FROM `games`
なるほど。
pluckは指定したカラムのみをSQLで取ってきている。
また、pluck必要なフィールドだけを読み込むことで、メモリの使用量も削減できるとの事で
これが圧倒的に早い理由らしい
→ pluckでメモリを大幅に節約する(翻訳)
mapの方が早いパターン
上の例だけみると常にpluckの方が早そうだけど、mapの方が早いパターンはあるのか?
調べてみた。
require 'bebnchmark'
users = User.all
Benchmark.bm 10 do |r|
r.report "pluck" do
2000.times { users.pluck(:id) }
end
r.report "map" do
2000.times { users.map(&:id) }
end
end
user system total real
pluck 4.725170 0.867798 5.592968 ( 6.395219)
map 1.070974 0.006997 1.077971 ( 1.079586)
この場合、mapの方が断然早い!
繰り返し処理を実行する場合、pluckは毎回SQLを発行してしまう。(この場合だと2000回発行してしまってます)
一方、mapは一回しか発行していない。
まとめ
- SQLの段階で必要なカラムだけを取ってこれるので、対象のレコードを配列に整形する場合などは
pluckが早い - 一方、繰り返し処理のなかで
pluckを使うと毎回SQLを発行してしまうので危険。その場合はmapを使った方が断然早い