/ Railsでの膨大なCSVエクスポートでのメモリ/メモリの問題 - ruby​​-on-rails、fastercsv

Ruby on Rails、fastercsvで大規模なCSVエクスポートのメモリ問題

データベースからcsvファイルに大量のデータをエクスポートしようとしていますが、非常に長い時間がかかり、大きなメモリ問題が発生する可能性があります。

メモリを増やすことなくCSVをエクスポートするためのより良い方法を誰かが知っていますか?もしそうなら、あなたは私にどのように見せることができますか?ありがとう。

ここに私のコントローラー:

def users_export
File.new("users_export.csv", "w")           # creates new file to write to
@todays_date = Time.now.strftime("%m-%d-%Y")
@outfile = @todays_date + ".csv"

@users = User.select("id, login, email, last_login, created_at, updated_at")

FasterCSV.open("users_export.csv", "w+") do |csv|
csv << [ @todays_date ]

csv << [ "id","login","email","last_login", "created_at", "updated_at" ]
@users.find_each do |u|
csv << [ u.id, u.login, u.email, u.last_login, u.created_at, u.updated_at ]
end
end

send_file "users_export.csv",
:type => "text/csv; charset=iso-8859-1; header=present",
:disposition => "attachment; filename=#{@outfile}"
end

回答:

回答№1の場合は7

あなたは1つの巨大な弦を作っているのでcsvファイル全体をメモリに保存します。あなたは「たくさんのメモリを使うことになる全てのユーザをロードしている。あなたが数百人か数千人のユーザしかいないとしても、何の違いもないが、あなたがたぶん2つのことをする必要があるだろう」

つかいます

User.find_each do |user|
csv << [...]
end

これにより、ユーザー全員ではなくバッチ(デフォルトで1000)にユーザーがロードされます。

全体をメモリにバッファするのではなく、csvをファイルに書き込むことも検討してください。一時ファイルを作成したとします。

FasterCSV.open("/path/to/file","w") do |csv|
...
end

あなたのcsvをファイルに書きます。あなたはその後使用することができます send_file それを送るために。すでにファイルを開いている場合は、 FasterCSV.new(io) うまくいくはずです。

最後に、レール3.1以降では、作成時にcsvファイルをストリーミングできるかもしれませんが、それは私が以前に試したことはありません。


回答№2については2

いいね!はい、もっと良い方法があります。 FasterCSV.generateは文字列をメモリに格納し、ブロックの最後に出力します。あなたは「使うほうがよい:

 FasterCSV.open(output_file, "w+") do |row|
row << my_row_data
end

これで各行がファイルに書き込まれます。send_dataではなく "send_file"。あるいは、本当に本当にsend_dataを実行しなければならないのであれば、ファイルが構築されている間それをすべて保持するのではなく、ファイルの内容を取得して送信してください(まだお勧めできません)


回答№3の場合は1

csv生成のヒントに加えて、データベースへの呼び出しも最適化するようにしてください。 必要な列だけを選択してください。

@users = User.select("id, login, email, last_login, created_at, updated_at").order("login")
@users.find_each do |user|
...
end

例えば1000人のユーザがいて、それぞれがpassword、password_salt、都市、国、... その後、1000個以下のオブジェクトがデータベースから転送され、ルビーオブジェクトとして作成され、最後にガベージコレクションされます。