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_slice
或in_groups
将result_set分割为较小的块会导致块内出错,因为这两个方法返回结果数组,而不是关系。
我对Ruby on Rails相当新,所以我的问题是:
任何指针/建议都会很受欢迎 - 谢谢!
答案 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