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