如何以优化方式复制/克隆ActiveRecord :: Relation

时间:2019-01-28 12:06:28

标签: ruby-on-rails ruby activerecord ruby-on-rails-5

我想以优化的方式克隆ActiveRecord::Base.transaction do data = MyModel.where(column_1: 'x') data.each do |item| new_item = item.dup new_item.column_2 = 'y' new_item.save! end end 对象的列表。也许我使用的方式已经过优化,但是我需要加快这一过程。这是我的代码

private def parallelFlatMapConcat[I, O](parallelism: Int)(sourceCreator: I => Source[O, NotUsed]) = {
  val mapConcat = Flow[I].flatMapConcat(sourceCreator)

  GraphDSL.create() { implicit builder =>
    import GraphDSL.Implicits._

    val balance = builder.add(Balance[I](parallelism))
    val merge = builder.add(Merge[O](parallelism))

    for (i ← 0 until parallelism)
      balance.out(i) ~> mapConcat ~> merge.in(i)

    FlowShape(balance.in, merge.out)
  }
}

也许有更好的方法一次复制记录列表,然后用一个查询更新所有记录。我尝试使用Google进行搜索,但到目前为止还没有运气。

3 个答案:

答案 0 :(得分:0)

如果您想尽快执行此操作,则可以使用SQL。

可以这样:

ActiveRecord::Base.connection.execute <<-SQL
   INSERT INTO my_models (column_1, column_2, column_3, ..)
      SELECT column_1, 'y', column_3, ..
      FROM my_models WHERE column_1 = 'x';
SQL

这应该在PostgreSQL和MySql中工作。

如果您有任何rails magic列(created_at,updated_at等),则必须在SQL中手动添加。

答案 1 :(得分:0)

如果我理解正确,您想复制满足条件的对象

(column_1: 'x')

您可以尝试这种方法,看起来它会执行相同的操作

MyModel.where(column_1: 'x').find_each { |u| u.dup.update(column2: 'y') }

但是慢一些(标为n = 1000)

<Benchmark::Tms:0x00007f96e6a1b970 @label="**dup.update**", @real=6.75463099999979, @cstime=0.0, @cutime=0.0, @stime=0.331546, @utime=2.2468139999999996, @total=2.5783599999999995>,

<Benchmark::Tms:0x00007f96e8cb23f8 @label="**dup.save!**", @real=6.470054999999775, @cstime=0.0, @cutime=0.0, @stime=0.32828900000000005, @utime=1.972385, @total=2.300674>

答案 2 :(得分:0)

短答案是使用single insert statement,而不是multiple inserts,即使如果它在一个DB transaction

here创业板将帮助你做到这一点。 (感谢bulk_insert