pluck
やmap
を利用することで、Active Recordモデルから特定の要素を取り出せます。
今回はpluck
とmap
の使い分けについて紹介します。
pluckについて
pluckはRailsのメソッドです。引数で指定したカラムのみをデータベースから直接取得します。
特定のカラムのみデータベースから取り出すためメモリを節約できるメリットがあります。
# pluckの引数(last_name)のみがSELECTに指定されている。
# last_name以外のカラムはSELECTされないのでメモリを節約できる
> User.all.pluck(:last_name)
(1.0ms) SELECT `users`.`last_name` FROM `users`
=> ["Cormier", "Reichert", "Hauck",...]
一方で、メソッド実行時に毎回SQLが発行されるというデメリットがあります。
mapについて
mapはRubyのメソッドです。ブロック内の処理を実行したレシーバを配列として返します。
mapはレシーバをメモリに読み込むためメモリを浪費するデメリットがあります。
# last_nameだけで十分なのにSELECTは全選択(*)になっている
# レシーバを加工するため、Userモデルが読み込まれることになる
> User.all.map(&:last_name)
User Load (2.0ms) SELECT `users`.* FROM `users`
=> ["Cormier", "Reichert", "Hauck",...]
pluckを利用したほうがよい場合
特定のカラムのみ利用する場合はメモリ節約の観点からpluck
を利用したほうがよいです。
# こっちよりは↓
> User.all.map(&:last_name)
# こっちのほうがいい↓
> User.all.pluck(:last_name)
mapを利用したほうがよい場合
インスタンス化されたActive Recordモデルから特定のカラムを取り出す場合はmap
を利用したほうがよいです。
pluck
ではインスタンスからカラムを取得する場合もSQLが実行されるため、処理が遅くなってしまいます。一方map
の場合SQLは毎回実行されません。
> users = User.limit(20)
# pluckでは毎回SQLが実行されている
> 5.times { users.pluck(:last_name) }
(0.7ms) SELECT `users`.`last_name` FROM `users` LIMIT 20
(0.4ms) SELECT `users`.`last_name` FROM `users` LIMIT 20
(0.5ms) SELECT `users`.`last_name` FROM `users` LIMIT 20
(0.5ms) SELECT `users`.`last_name` FROM `users` LIMIT 20
(0.4ms) SELECT `users`.`last_name` FROM `users` LIMIT 20
=> 5
# mapでは毎回SQLが実行されない
> 5.times { users.map(&:last_name) }
User Load (0.7ms) SELECT `users`.* FROM `users` LIMIT 20
=> 5
こちらのコメントにもあるように、最近のpluck
はSQLの再発行を防ぐ実装になっているため、場合によっては毎回SQLが実行されません。
ですが、インスタンスからカラムを取得する場合はmap
を利用しておいたほうが無難です。
まとめ
- 特定のカラムを取得するだけで十分な場合はpluckを利用する
- インスタンス化されたActive Recordモデルからカラムを取得する場合はmapを利用する
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!