2014-01-14 27 views
12

我正在使用活动记录来获取我的故事,然后生成一个CSV,标准的方式在轨道铸造中完成。但是我有很多行,需要几分钟时间。我想如果我可以让posgresql做csv渲染,那么我可以节省一些时间。导航原始查询的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结果返回给导轨。

UPDATE

得到了120000毫秒的CSV出口下降到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)) 
+0

有没有办法直接从数据库发送'send_data'?我的意思是,没有将它保存到'csv'数组中? –

+0

@FernandoFabreti听起来像copy_data函数返回的行需要连接在一起成为一个文件。如果没有某种变量赋值,我不认为它们是组合这些行的方式。你可以从头开始使用一个字符串,然后在循环中追加。会对性能差异感兴趣。 – penner

+0

我不得不将'csv.join(“\ r \ n”)'改为'csv.join(“\ n”)'使它正确地产生行。它最初增加了一个额外的换行符。不知道这是否会影响其他非* nix机器... – allthesignals

回答

11

据我所知,你需要使用copy_data方法此底层PostgreSQL数据库连接:

- (对象)copy_data(SQL)

呼叫-SEQ:

conn.copy_data(sql) {|sql_result| ... } -> PG::Result 

执行的复制处理进行数据传送[原文如此]或从服务器。

这会通过#exec发出SQL COPY命令。对此的响应(如果命令中没有错误)是一个PG::Result对象,该对象传递给该块,并带有状态码PGRES_COPY_OUT或PGRES_COPY_IN(取决于指定的复制方向)。然后,应用程序应该使用#put_copy_data#get_copy_data来接收或传输数据行,并在完成后从块中返回。

甚至还有一个例子:

conn.copy_data "COPY my_table TO STDOUT CSV" do 
    while row=conn.get_copy_data 
    p row 
    end 
end 

的ActiveRecord的包装为原料数据库连接不知道什么copy_data是,但你可以使用raw_connection解开它:

conn = ActiveRecord::Base.connection.raw_connection 
csv = [ ] 
conn.copy_data('copy stories to stdout with csv header') do 
    while row = conn.get_copy_data 
    csv.push(row) 
    end 
end 

那会在csv(每个数组条目的一个CSV行)中留下一串CSV字符串,您可以使用csv.join("\r\n")来获取最终的CSV数据。

+0

最后必须使用不同的查询,这种查询可以更好地转义数据。 conn.copy_data(“将故事复制到标准输出(格式为CSV,标题为TRUE,FORCE_QUOTE *,ESCAPE E'\\\');”)。谢谢你的帮助! – penner

相关问题