【问题标题】:ActiveRecord Rails - create a batch of empty recordsActiveRecord Rails - 创建一批空记录
【发布时间】:2018-03-01 03:37:44
【问题描述】:

在我的 rails 应用程序中,我有一个模型说“服务器”,它有很多“虚拟机”。当一个服务器记录配置为有 50 个虚拟机时,我想立即创建 50 个 VirtualMachine 的空记录。 1) id: 1, start_time: nil, space: nil 2) id: 2, start_time: nil, space: nil 3) id: 3, start_time: nil, space: nil 4) id: 4, start_time: nil, space: nil ... 50) id: 50, start_time: nil, space: nil

我知道这可以通过 for 循环和创建/新建来实现。但是有没有一种 ActiveRecord 方法可以在没有循环的情况下执行此操作,从而减少从我的应用程序对数据库的调用次数?

谢谢, 格雷格

【问题讨论】:

  • 作为后台作业使用块:n.times { Model.create! }
  • @Emu 即便不占用网络服务器,也依然非常无效。

标签: sql ruby-on-rails activerecord


【解决方案1】:

看看activerecord-import gem。它像您描述的那样处理批量插入,同时将 ActiveRecord 查询的数量保持在最低限度。由于您要创建如此多的记录,因此在后台作业中执行此操作可能是一个好主意。

【讨论】:

  • 这很好用。我可以使用 delete_all 进行批量删除。谢谢!
【解决方案2】:

如果您想创建多个没有实际数据的记录,您想编写一个一次性插入所有记录的 SQL 查询,而不是使用将创建 50 个单独查询的.create

ActiveRecord 没有内置的批量插入规定。您可以使用 gem 或编写自己的 gem,这对于这个用例来说非常简单。

您可以一次插入多行,例如:

INSERT INTO virtual_machines (server_id) VALUES (1), (1),...

您可以使用简单的字符串操作来添加所有这些值:

"INSERT INTO virtual_machines (server_id) VALUES " + Array.new(50, "(#{id})").join(', ')

您应该能够忽略所有没有值的列,因为无论如何它们都应该由数据库默认值处理。

要执行 SQL 语句,请使用 self.connection.execute。将其包装在交易中可能是谨慎的:

class Server < ApplicationRecord
  def self.create_with_children(**attributes)
    self.transaction do
      record = self.create!(attributes)
      self.connection.execute(
        'INSERT INTO virtual_machines (server_id) VALUES ' + 
        Array.new(50, "(#{record.id})").join(',')
      )
      record
    end
  end
end

由于它是单个查询,因此执行时间很可能与插入单行相当,并且使用后台作业是过早的优化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    相关资源
    最近更新 更多