Tech Racho エンジニアの「?」を「!」に。
  • 開発

Rails: pluckでメモリを大幅に節約する(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Rails: pluckでメモリを大幅に節約する(翻訳)

Active Recordのモデルは信じられないほど柔軟性が高く、機能が山ほど搭載されています。メソッドのAPIが大量にあるため、Active Recordの個別のオブジェクトはメモリに読み込まれると非常に場所を取ります。

Active Recordのモデルにフィールドがたった1つあるだけでも(たとえばidだけでも)、Railsが背後に控えているのです。

次のように書くのではなく

多数のオブジェクトをイテレーションしてメモリに全部読み込む。

Book.paperbacks.map { |book| book.title }
#=> ["Eloquent Ruby", "Sapiens", "Agile Web Development With Rails"]
Book.paperbacks.map(&:title)
#=> ["Eloquent Ruby", "Sapiens", "Agile Web Development With Rails"]

次のように書く

ActiveRelation#pluckメソッドを用いて、必要なフィールドをデータベースから直接読み込む。

Book.paperbacks.pluck(:title)
#=> ["Eloquent Ruby", "Sapiens", "Agile Web Development With Rails"]

そうする理由

この方法は、スピードとメモリ使用量の効率に関連します。

Active Recordモデルが大量のメモリを食う問題は、特に巨大なコレクションを操作するときにつらくなります。最初の例では、データベースから読み込まれた行をひとつひとつオブジェクトに変換しているにもかかわらず、たった1つのフィールドしか使っていません。Railsがメモリ上に用意する、モデルのその他の機能は必要ありません。

必要なフィールドだけを読み込むことで、アプリが高速化し、メモリ使用量も削減されます。

そうしない理由があるとすれば

#pluckメソッドがリクエストに応じて返す値は、Rubyの素の配列のみです。モデルのメソッドは一切読み込まれません。

Active Recordの実際のオブジェクトがどうしても必要な場合や、#pluckの後でモデルを更新する必要がある場合は、残念ながら使えません。

素の配列の代わりに、スコープに続けてselectすることでActive Recordの完全なモデルを使うことを検討してもよいのです、リクエストするフィールドしか含まれません。#pluckほどメモリ効率のよい方法は他にありません。

Book.paperbacks.select(:title).map { |book| book.title }
#=> ["Eloquent Ruby", "Sapiens", "Agile Web Development With Rails"]

関連記事

Rails: モデルの外では名前付きスコープだけを使おう(翻訳)

Rails: ActiveRecord::Relationで生SQLは避けよう(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。