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は避けよう(翻訳)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ