我使用Active Record获取我的故事,然后生成一个CSV,这是Rails Cast中的标准方式。但是我的行数很多,需要花费数分钟的时间。我认为如果我可以让PostgreSQL来进行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 }
这适用于普通查询,我只是无法弄清楚SQL语法,以便将CSV结果返回到Rails。
更新:
将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))
csv.join("\r\n")
更改为csv.join("\n")
,以便正确生成行。最初它会添加一个额外的换行符。不确定这是否会影响其他非*nix机器... - allthesignalsself.response_body
,就像这里使用的那样(https://coderwall.com/p/kad56a/streaming-large-data-responses-with-rails)。链接中的示例不完整,需要在生成行之前添加lines << "#{row.length.to_s(16)}\r\n"
以使分块响应正常工作。 - mlt