[英]Import CSV data faster in rails
我正在構建導入模塊,以從csv文件導入大量訂單。 我有一個稱為Order的模型,需要在其中存儲數據。
訂單模型的簡化版本如下
sku
quantity
value
customer_email
order_date
status
導入數據時,必須發生兩件事
目前,我使用一個簡單的csv導入代碼
CSV.foreach("orders.csv") do |row|
order = Order.first_or_initialize(sku: row[0], customer_email: row[3])
order.quantity = row[1]
order.value= parse_currency(row[2])
order.order_date = parse_date(row[4])
order.status = row[5]
order.save!
end
其中parse_currency和parse_date是兩個用於從字符串中提取值的函數。 對於日期,它只是Date.strptime的包裝。
我可以添加檢查以查看記錄是否已經存在,並且在該記錄已經存在的情況下不進行任何操作,這樣可以節省一些時間。 但是我正在尋找更快的東西。 當前,使用一個空數據庫導入大約10萬行大約需要30分鍾。 隨着數據大小的增加,它會變慢。
因此,我基本上是在尋找一種更快的方式來導入數據。
任何幫助,將不勝感激。
編輯
在根據評論進行更多測試之后,我有一個觀察和一個問題。 我不確定他們是否應該去這里,或者我是否需要打開一個新線程來解決這些問題。 因此,請讓我知道是否需要將其移至另一個問題。
我使用Postgres副本進行了測試,以從文件中導入數據,耗時不到一分鍾。 我只是將數據導入到新表中而沒有任何驗證。 因此導入可以更快。
Rails的開銷似乎來自2個地方
現在我的問題。 如何將更新/創建邏輯移動到數據庫,即,如果基於sku和customer_email的訂單已經存在,則需要更新記錄,否則需要創建新記錄。 當前使用rails,我正在使用first_or_initialize方法來獲取記錄(如果記錄存在)並對其進行更新,否則我將創建一個新記錄並保存它。 如何在SQL中做到這一點。
我可以使用ActiveRecord連接執行來運行原始SQL查詢,但我認為這不是一種非常優雅的方法。 有更好的方法嗎?
從ruby 1.9開始,fastcsv現在是ruby核心的一部分。 您不需要使用特殊的寶石。 只需使用CSV
。
擁有10萬條記錄,紅寶石需要0.018秒/條記錄。 我認為您的大部分時間都將在Order.first_or_initialize
。 代碼的這一部分需要額外往返數據庫。 ActiveRecord
初始化也需要花費時間。 但確實可以確保我建議您對代碼進行基准測試。
Benchmark.bm do |x|
x.report("CSV evel") { CSV.foreach("orders.csv") {} }
x.report("Init: ") { 1.upto(100_000) {Order.first_or_initialize(sku: rand(...), customer_email: rand(...))} } # use rand query to prevent query caching
x.report('parse_currency') { 1.upto(100_000) { parse_currency(...} }
x.report('parse_date') { 1.upto(100_000) { parse_date(...} }
end
在導入期間,您還應該注意內存消耗。 也許垃圾收集運行不頻繁或對象沒有被清理。
要提高速度,您可以遵循Matt Brictson提示並繞過ActiveRecord
。 您可以嘗試使用gem activerecord-import
,也可以開始並行進行,例如使用fork
進行多處理或使用Thread.new
多線程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.