ActiveRecord交易,可以节省1000多个条目

时间:2013-02-28 23:28:48

标签: ruby-on-rails activerecord transactions

我有一个如下所示的EventsController创建操作:

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 action提交的文件。

除了许多其他方面之外,

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

我找到了解决这个问题的方法。包裹控制器在ActiveRecord :: Base.transaction中创建操作:

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

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

虽然此解决方案正常运行,但只创建一个事务,并将整个过程加速约60次。这是解决这个问题的好方法吗?当然交易还没有为此设计?从包含超过一千个条目的文件创建记录的其他选项是什么?

2 个答案:

答案 0 :(得分:3)

缓慢运行流程的最佳解决方案是使用delayed_jobresquesidekiq等后台作业。

答案 1 :(得分: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 activerecord-import

data = []
@data.each do |pick_arguments|
  data << Pick.new(pick_arguments)
end
Pick.import books