29

我想在我的Rails應用程序中對數據庫(在我的情況下爲POSTGRES)進行批量插入數千條記錄。批量插入導軌3

這樣做的「Rails方式」是什麼? 一些快速且正確的做法。

我知道我可以通過字符串連接的屬性創建SQL查詢,但我想要一個更好的方法。

+0

參見:如何實現在Rails的批量插入3] (http://stackoverflow.com/questions/8505263/how-to-implement-bulk-insert-in-rails-3)和[批量插入記錄到活動記錄表(http://stackoverflow.com/questions/ 15317837 /大容量插入 - 記錄 - 進入 - 活性 - 記錄表)。 – 2014-04-13 05:06:17

回答

49

ActiveRecord .create方法支持批量創建。如果數據庫不支持該方法,並且在支持該功能的情況下使用底層數據庫引擎,則該方法會模擬該功能。

只需傳遞一組選項。

# Create an Array of new objects 
User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) 

支持塊,這是共享屬性的常用方法。

# Creating an Array of new objects using a block, where the block is executed for each object: 
User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u| 
    u.is_admin = false 
end 
+0

所以你認爲對於postgres的情況它會創建一個單一的插入語句? – phoenixwizard

+2

它可能取決於驅動程序版本和PG版本。您可以在您的控制檯中嘗試它並查看執行的SQL語句。 –

+2

它似乎在創建單獨的查詢。儘管通過交易包圍它似乎在加快速度。任何方式,我可以確保單個查詢插入? – phoenixwizard

1

您可以創建在你的軌道模型中的腳本,編寫查詢該腳本 插入在軌可以運行使用

rails runner MyModelName.my_method_name 

的是,我在我的項目中使用的最佳方法腳本。

更新:

我使用後在我的項目,但它是不恰當的SQL注入攻擊。 如果您未在此查詢中使用用戶的輸入,可能你

user_string = " ('[email protected]','a'), ('[email protected]','b')" 
User.connection.insert("INSERT INTO users (email, name) VALUES"+user_string) 

多個記錄的工作:

new_records = [ 
    {:column => 'value', :column2 => 'value'}, 
    {:column => 'value', :column2 => 'value'} 
] 

MyModel.create(new_records) 
+0

我正在尋找像在單個查詢中插入1000個對象到數據庫中的東西。 用例:我從Facebook登錄用戶,並通過一次數據庫調用保存所有Facebook朋友。 – phoenixwizard

+0

嗨,@Aram Bhusal,請看我最新的答案。 –

+0

這正是我想避免:)看來它要麼這樣或更慢的方式... – phoenixwizard

0

你能做到快速路或Rails的方式;)的根據我的經驗,將大量數據導入到Postgres的最佳方式是通過CSV。使用Postgres的本地CSV導入功能需要幾分鐘的時間Rails方式需要幾秒鐘的時間。

http://www.postgresql.org/docs/9.2/static/sql-copy.html

它甚至觸發數據庫觸發器和尊重數據庫的約束。

編輯(在您的評論之後): Gotcha。在那種情況下,你已經正確地描述了你的兩個選擇我之前一直處於同樣的狀況,使用Rails 1000保存實現它!策略,因爲這是最簡單的工作,然後將其優化爲「追加龐大的查詢字符串」策略,因爲它的表現更好。

當然,不成熟的優化是所有邪惡的根源,所以也許可以使用簡單的慢速Rails方法,並且知道構建一個大的查詢字符串是一個完美合法的技術,以犧牲維護性爲代價進行優化。我覺得你真正的問題是'是否有Railsy的方式,不涉及1000年的查詢?' - 不幸的是,答案是否定的。

+0

我覺得我的問題不清楚。 我正在考慮用戶使用他的Facebook帳戶登錄的用例,我正在保存他的所有朋友。我一次預計大約有1000到4000條記錄。我想從我的Rails應用程序中做到這一點 – phoenixwizard

17

@Simone Carletti和@Sumit Munot的兩個答案後,我終於達成了一個解決方案。

直到Postgres的驅動程序支持的ActiveRecord .create方法的批量插入,我想一起去activerecord-import gem。它在一個插入語句中進行批量插入。

books = [] 
10.times do |i| 
    books << Book.new(:name => "book #{i}") 
end 
Book.import books 

在POSTGRES這導致單個插入statemnt。

一旦Postgres的驅動程序支持在單個插入語句ActiveRecord的.create方法的批量插入,然後@Simone Carletti酒店的解決方案更有意義:)

+1

不幸的是,這仍然是這樣一個簡單問題的最佳解決方案。 「寫入原始數據庫」解決方案的工作原理可能比較簡單,但如果您不止一次地這樣做,那麼這個gem就是最好的解決方案,不會在任何地方散佈原始sql(或其他語言)。 –

+0

它說缺少的方法是postgres-9.4,Ubuntu 14.04,rails 4.2 – Anwar

+1

@Anwar:你的gemfile中有'gem'activerecord-import''嗎?這是使用'Model#import'所必需的。 – Pete