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
を使った方が断然早い