2013-10-10

Railsで大量データを扱うときはpluckを使ってみるのも一案のようです

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Railsで大量データを取得してeachでまわすと遅いです。

これは取得したデータすべてにActiveRecordオブジェクトを生成していることが原因でもあるようです。

なので対策として考えられるのは、生成するオブジェクトの数を減らす方法があります。

これにはfind_eachを使うと実現できます。

find_eachは指定した件数づつ(デフォルトでは1000件)データを取得して、その分だけのActiveRecordオブジェクトを生成します。
find_eachに関しては、過去に紹介していますので、そちらをご覧ください。
大量のデータをActiveRecordで処理するとき

find_eachはソート順を指定できないという欠点があります。


もう一つの方法としてActiveRecordオブジェクトを生成せずに配列なりハッシュなり、ActiveRecordよりも軽いオブジェクトを生成する方法があります。

これには、pluckを使えます。
以下のような感じで利用します。

Order.where( amount: 1000 ).pluck( :order_no, :name, :address )
 # => [["O123", "テスト太郎", "トーキョー"],["O456", "テスト花子", "オーサカ"]]

pluckの方では、ソート順は指定できます。

pluckに複数のカラムを指定できるのは、Rails4.0からのようで3.2では一つのカラムしか指定できません。

3.2でpluckで複数のカラムを指定するには、以下の方法でpluck_allという複数カラムを利用できるようなpluckを定義するパッチをあてる方法があります。
http://meltingice.net/2013/06/11/pluck-multiple-columns-rails/

こちらではハッシュのやり方ではハッシュでデータを取得します。

Order.where( amount: 1000 ).pluck_all( :order_no, :name, :address )
 # => [{:order_no => "O123", :name => "テスト太郎", :address => "トーキョー"},
          {:order_no => "O456", :name => "テスト花子", :address => "オーサカ"}]


もう一つの方法でmultipluckというgemを使う方法もあります。
https://github.com/hanzq/multipluck

こちらは私は試していないのですが、Rails4.0と同じ感じ使えそうなので将来のアップデートを見据えるとこちらもよさそうな気がします。


で、find_eachとpluckのどちらが速いかなのですが、私が試した数万件のデータを処理するケースではだいたい同じぐらいでした。
どちらもeachでまわすよりかは、断然早くなっています。
なのでどちらを利用するかはケースバイケースなのかなぁという感じです。


コメントを投稿