【发布时间】:2014-02-03 06:23:45
【问题描述】:
我使用活动记录来获取我的故事,然后生成一个 CSV,这是在 rails cast 中完成的标准方式。但是我有很多行,这需要几分钟。我想如果我可以让 posgresql 进行 csv 渲染,那么我可以节省一些时间。
这是我现在拥有的:
query = "COPY stories TO STDOUT WITH CSV HEADER;"
results = ActiveRecord::Base.connection.execute(query);
但是这个查询的结果是空的:
=> #<PG::Result:0x00000006ea0488 @connection=#<PG::Connection:0x00000006c62fb8 @socket_io=nil, @notice_receiver=nil, @notice_processor=nil>>
2.0.0-p247 :053 > result.count
=> 0
更好的了解方式:
2.0.0-p247 :059 > result.to_json
=> "[]"
我怀疑我的控制器看起来像这样:
format.csv { send_data raw_results }
这适用于普通查询,我只是无法弄清楚将 CSV 结果返回到 rails 的 SQL 语法。
更新
将 CSV 导出从 120000 毫秒降至 290 毫秒
我的模特:
def self.to_csv(story_ids)
csv = []
conn = ActiveRecord::Base.connection.raw_connection
conn.copy_data("COPY (SELECT * FROM stories WHERE stories.id IN (#{story_ids.join(',')})) TO STDOUT WITH (FORMAT CSV, HEADER TRUE, FORCE_QUOTE *, ESCAPE E'\\\\');") do
while row = conn.get_copy_data
csv.push(row)
end
end
csv.join("\r\n")
end
我的控制器:
send_data Story.to_csv(Story.order(:created_at).pluck(:id))
【问题讨论】:
-
有什么办法可以直接从 DB 到
send_data吗?我的意思是,不将其保存到csv数组中? -
@FernandoFabreti 听起来 copy_data 函数会返回需要合并到一个文件中的行。我认为没有某种变量分配的情况下没有任何方法可以组合行。您可能可以从头开始使用字符串并附加到循环中。会对性能差异感兴趣。
-
我必须将
csv.join("\r\n")更改为csv.join("\n")才能正确生成行。它最初是添加一个额外的换行符。不确定这是否会影响其他非 *nix 机器... -
@penner 对我来说也很有魅力,感谢您的更新!不过,有两个简单的问题: 1. 当一行由多个涉及关联的复杂 AR 查询生成时,情况如何?然后我们如何生成单个 SQL 查询并在上面的示例中传递它? 2. 虽然它肯定会影响时间方面的性能,但它是否也会影响操作使用的内存?
-
@FernandoFabreti 我最终将答案包装到 Enumerator 中,然后传递给
self.response_body,就像使用的 here 一样。链接的示例不完整,需要lines << "#{row.length.to_s(16)}\r\n"才能产生一行以使分块响应起作用。
标签: postgresql csv ruby-on-rails-4 rails-activerecord pg