🚮

【Rails】ActiveRecord の select メソッドでインスタンスを軽量化しよう

2024/08/26に公開

こんにちは!
ラブグラフエンジニアのひろです。
今回は、インスタンスを軽量化して負荷を減らすことができる select メソッドについてです。
いくつか注意点もあるので、ぜひ最後まで読んでいってください。

はじめに

大量のデータを処理しなければならないとき、 ActiveRecord の select メソッドは負荷軽減のための有効な手段となり得ます。
この記事では、 select メソッドの基本的な使い方から、似たメソッドである pluck との違い、使用する際の注意点まで解説します。

select メソッドとは

select メソッドは、 ActiveRecord のクエリメソッドの一つで、データベースから取得するカラムを限定することができます。
Rails ガイド:特定のフィールドだけを取り出す

通常のクエリでは、モデルに対応するテーブルの全カラムが取得されますが、 .select を使うことで必要なカラムだけを取得することができます。

# すべての User を取得
users = User.all
# User Load (2.5ms)  SELECT `users`.* FROM `users`
# =>
# [#<User:0x0000ffff32862bfs
#  id: 1,
#  name: "hiro",
#  email: "a@test.com"
#  age: nil,
#  birthday: nil,
#  avator: nil,
#  created_at: Mon, 19 Aug 2024 12:00:00.387980000 JST +09:00,
#  updated_at: Mon, 19 Aug 2024 12:00:00.387980000 JST +09:00>,
# ...

# User モデルから name と email カラムだけを取得する
users = User.select(:name, :email)
# User Load (1.2ms)  SELECT `users`.`name`, `users`.`email` FROM `users`
# =>
# [#<User:0x0000ffff32862bfs id: nil, name: "hiro", email: "a@test.com">,
# ...

select メソッドでできること

select メソッドを使うことで、次のようなメリットがあります。

  • SQLクエリのパフォーマンス向上
    • 取得するデータ量が少なくなるため、SQLクエリの実行時間が短縮される
  • メモリ使用量の削減
    • 軽量化されたインスタンスを使用することで、メモリ使用量が減る
  • インスタンスメソッドが使える
    • 軽量化しつつもインスタンスの形を保っているため、メソッドを呼び出すことができる

pluck との違い

ActiveRecord の pluck メソッドも特定のカラムを取得するために使用されますが、 pluck は配列を返し、 select は ActiveRecord の Relation オブジェクトを返すという違いがあります。

# User モデルから name, email カラムだけを配列として取得する
name_and_emails = User.pluck(:name, :email)
# SELECT `users`.`name`, `users`.`email` FROM `users`
# =>
# [["hiro", "a@test.com"],
# ...

必要なデータがカラムの値だけなのか、それともインスタンスの状態で欲しいのか、適切に使い分けましょう。

select メソッドを使用する際の注意点

select で指定しなかったカラムにアクセスしようとすると、例外が発生します。

user = User.select(:name, :email).first
user.age # age カラムが存在していたとしても、 select に含めていないので NoMethodError が発生する

その場で処理するだけなら良いですが、そのインスタンスを各所で使い回している場合、
未来の自分が NoMethodError に遭遇することが十分考えられるため、コメントで明示するか、変数名で特定のカラムしか取得していないことを表現するのが良いでしょう。

まとめ

このように select メソッドを使うことで、インスタンスの形を保ったまま、パフォーマンスの向上を目指すことができます。
大量のデータを扱う際には、インスタンスのすべての情報が必要かどうか考えてみて、 select メソッドの活用を検討してみてください。

ラブグラフのエンジニアブログ

Discussion