簡體   English   中英

在Rails中更快地導入CSV數據

[英]Import CSV data faster in rails

我正在構建導入模塊,以從csv文件導入大量訂單。 我有一個稱為Order的模型,需要在其中存儲數據。

訂單模型的簡化版本如下

sku
quantity
value
customer_email
order_date
status

導入數據時,必須發生兩件事

  1. 需要清除任何日期或貨幣,即日期在csv中以字符串表示,需要將其轉換為Rails Date對象,並且需要通過除去任何逗號或美元符號將貨幣轉換為十進制
  2. 如果已經存在一行,則必須對其進行更新,則根據兩列檢查唯一性。

目前,我使用一個簡單的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個地方

  1. 正在發生的多個數據庫調用,即每行的first_or_initialize。 這最終成為多個SQL調用,因為它必須首先找到記錄,然后對其進行更新然后保存。
  2. 帶寬。 每次調用SQL Server時,數據都會來回流動,這會占用大量時間

現在我的問題。 如何將更新/創建邏輯移動到數據庫,即,如果基於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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM