2014-01-14 29 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

相關問題