2

次のような EventsController create アクションがあります。

class EventsController < ApplicationController

  def create
    @event = Event.new(params[:event].slice(*Event.accessible_attributes))
    if @event.save
      DraftBuilder.new(event: @event).build(params[:event][:file].path) 
      redirect_to @event
    else
      render :new
    end
  end

end

params[:event][:file]は、ユーザーが file_field_tag を介して Event#new アクションを介して送信できるファイルです。

DraftBuilder#buildメソッドは、とりわけ、特定のファイルを解析し、データベースに約 1000 のレコードを作成します (複数のテーブルにわたってデータベースにデータを保存します)。

私が抱えている問題は、DraftBuilder#build が非常に遅いことです。レコードをループで保存していて、保存するたびに Active Record が新しいトランザクションを作成するため、処理が遅くなります。

単純化された DraftBuilder#build は次のようになります。

class DraftBuilder
  def build(file)
    @data = parse(file) #@data is an array of hashes with 1000+ records
    @data.each do |pick_arguments|
      Pick.create(pick_arguments)
    end
  end
end

この問題の解決策を 1 つ見つけました。コントローラー作成アクションを ActiveRecord::Base.transaction にラップします。

class EventsController < ApplicationController
  around_filter :transactions_filter, only: [:create]

    def transactions_filter
      ActiveRecord::Base.transaction do
        yield
      end
    end
end        

このソリューションが機能している間、トランザクションは 1 つだけ作成され、プロセス全体が約 60 倍高速化されます。この問題に取り組む良い方法ですか?? 確かにトランザクションはこれのために設計されていませんか?? 1000 を超えるエントリを持つファイルからレコードを作成するための他のオプションは何ですか??

4

2 に答える 2

3

実行中のプロセスを遅くする最善の解決策は、delayed_job、resque、sidekiq などのバックグラウンド ジョブ使用することです

于 2013-02-28T23:32:06.630 に答える
2

次の 2 つの方法があります。

それ以外の

@data.each do |pick_arguments|
  Pick.create(pick_arguments)
end
  1. 取引
     ActiveRecord::Base.transaction do
       @data.each do |pick_arguments|
         Pick.create(pick_arguments)
       end
     end  
    
  2. Gem のアクティブレコードのインポート
    data = []
    @data.each do |pick_arguments|
      data << Pick.new(pick_arguments)
    end
    Pick.import data
    
于 2013-02-28T23:33:39.103 に答える