【问题标题】:Breaking Association/ Relation collection objects into smaller Association/ Relation collections in Ruby on Rails在 Ruby on Rails 中将关联/关系集合对象分解为更小的关联/关系集合
【发布时间】:2016-01-13 19:26:04
【问题描述】:

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 还很陌生,所以我的问题是:

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

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

【问题讨论】:

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


    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2018-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多