在Ruby on Rails中将关联/关系集合对象分解为较小的关联/关系集合

时间:2015-10-15 11:04:03

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord relation

JRuby,Rails 3

我有一段代码可以查询许多表,通过关联相关,将组合结果集作为ActiveRecord :: Relation返回。我的问题是,当这个函数检索一个非常大的结果集并试图用它做某事(在我的情况下,创建一个.xls文件),JVM错误,报告一个GC内存堆问题。

问题部分在于,当尝试处理.xls导出时,所有这些记录都保存在内存中,以及JRuby的可疑垃圾收集器 - 但是,所有这些记录都不应该立即处理!所以我的解决方案是将这些记录分成更小的块,将它们写入文件并重复。

但是,在我所有其他约束中,我需要使用的下一部分代码需要传递给它的关系对象。以前,这是整个结果集,但在这一点上,我把它分解成更小的位(为了论证,让我们说100条记录)。

此时,您可能正在思考,是的 - 这是什么问题?好吧,请参阅下面的示例代码:

#result_set = relation object
result_set.scoped.each_slice(100) do |chunk|
  generic_filter = App::Filter.new(chunk, [:EXCEL_EXPORT_COLUMNS]) #<-- errors here

  #do some stuff
  generic_filter.relation.each_with_index do |work_type, index|
    xls_doc.row(index + 1).concat(generic_filter.values_for_row(work_type))
    DATE_COLUMN_INDEX.each do |column_index|
      xls_doc.row(index + 1).set_format column_index, 
           ::Spreadsheet::Format.new(number_format: 'DD-MM-YYYY')
    end
  end
  [...] #some other stuff
end    

正如您所看到的,我将result_set拆分为100个记录的较小块,并将其传递给期望关系对象的App :: Filter类。但是,使用each_slicein_groups将result_set分割为较小的块会导致块内出错,因为这两个方法返回结果数组,而不是关系。

我对Ruby on Rails相当新,所以我的问题是:

  • 关系实际上是一个对象/集合/或类似于预先的事物 定义的查询,就像准备好的语句一样?
  • 是否可以使用类似的方法返回较小的关系对象 each_slice或in_groups并按预期处理它们?

任何指针/建议都会很受欢迎 - 谢谢!

1 个答案:

答案 0 :(得分:1)

关系是构建SQL查询(INSERT,SELECT,DELETE等)的一种帮助。在您的例子中,您使用each_slice触发SELECT查询,并获得结果数组。

我没有检查过,我不确定each_slice正在做你想做的事情......你应该检查一下find_each

你应该做这样的事情:

# do what you need with the relation but do NOT trigger the query
generic_filter = App::Filter.new(result_set.scoped, [:EXCEL_EXPORT_COLUMNS]) #<-- errors here

# trigger the query by slice
generic_filter.relation.find_each do |chunk|
  chunk.each_with_index do |work_type, index|
    xls_doc.row(index + 1).concat(generic_filter.values_for_row(work_type))
    DATE_COLUMN_INDEX.each do |column_index|
      xls_doc.row(index + 1).set_format column_index, 
           ::Spreadsheet::Format.new(number_format: 'DD-MM-YYYY')
    end
  end
end