Ruby-on-rails 在 rails 中一次更新多条记录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5394699/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 00:44:58  来源:igfitidea点击:

Updating several records at once in rails

ruby-on-rails

提问by brycemcd

In a rails 2 app I'm building, I have a need to update a collection of records with specific attributes. I have a named scope to find the collection, but I have to iterate over each record to update the attributes. Instead of making one query to update several thousand records, I'll have to make several thousand queries.

在我正在构建的 rails 2 应用程序中,我需要更新具有特定属性的记录集合。我有一个命名范围来查找集合,但我必须遍历每条记录以更新属性。与其进行一次查询来更新数千条记录,不如进行数千次查询。

What I've found so far is something like Model.find_by_sql("UPDATE products ...)

到目前为止我发现的是 Model.find_by_sql("UPDATE products ...)

This feels really junior, but I've googled and looked around SO and haven't found my answer.

这感觉真的很初级,但我用谷歌搜索并环顾四周,但没有找到我的答案。

For clarity, what I have is:

为了清楚起见,我所拥有的是:

ps = Product.last_day_of_freshness
ps.each { |p| p.update_attributes(:stale => true) }

What I want is:

我想要的是:

Product.last_day_of_freshness.update_attributes(:stale => true)

回答by Brett Bender

It sounds like you are looking for ActiveRecord::Base.update_all- from the documentation:

听起来您正在寻找ActiveRecord::Base.update_all- 从文档中:

Updates all records with details given if they match a set of conditions supplied, limits and order can also be supplied. This method constructs a single SQL UPDATE statement and sends it straight to the database. It does not instantiate the involved models and it does not trigger Active Record callbacks or validations.

如果所有记录与提供的一组条件匹配,则使用给出的详细信息更新所有记录,也可以提供限制和顺序。此方法构造单个 SQL UPDATE 语句并将其直接发送到数据库。它不会实例化所涉及的模型,也不会触发 Active Record 回调或验证。

Product.last_day_of_freshness.update_all(:stale => true)

Actually, since this is rails 2.x (You didn't specify) - the named_scope chaining may not work, you might need to pass the conditions for your named scope as the second parameter to update_all instead of chaining it onto the end of the Product scope.

实际上,由于这是 rails 2.x(您没有指定)-named_scope 链接可能不起作用,您可能需要将命名范围的条件作为第二个参数传递给 update_all,而不是将其链接到末尾产品范围。

回答by Taryn East

Loos like update_all is the best option... though I'll maintain my hacky version in case you're curious:

好像 update_all 是最好的选择……不过我会保留我的 hacky 版本,以防你好奇:

You can use just plain-ole SQL to do what you want thus:

您可以只使用普通的 ole SQL 来执行您想要的操作:

ps = Product.last_day_of_freshness
ps_ids = ps.map(%:id).join(',') # local var just for readability
Product.connection.execute("UPDATE `products` SET `stale` = TRUE WHERE id in (#{ps_ids)")

Note that this is db-dependent - you may need to adjust quoting style to suit.

请注意,这取决于数据库 - 您可能需要调整引用样式以适应。

回答by yozzz

For those who will need to update big amount of records, one million or even more, there is a good way to update records by batches.

对于那些需要更新大量记录,百万甚至更多的人来说,有一个批量更新记录的好方法。

product_ids = Product.last_day_of_freshness.pluck(:id)
iterations_size = product_ids.count / 5000

puts "Products to update #{product_ids.count}"

product_ids.each_slice(5000).with_index do |batch_ids, i|
  puts "step #{i} of iterations_size"
  Product.where(id: batch_ids).update_all(stale: true)
end

If your table has a lot indexes, it also will increase time for such operations, because it will need to rebuild them. When I called update_allfor all records in table, there were about two million records and twelve indexes, operation didn't accomplish in more than one hour. With this approach it took about 20 minutes in development env and about 4 minutes in production, of course it depends on application settings and server hardware. You can put it in rake taskor some background worker.

如果你的表有很多索引,它也会增加此类操作的时间,因为它需要重建它们。当我调用update_all表中的所有记录时,大约有200万条记录和12个索引,操作在一个多小时内没有完成。使用这种方法,开发环境大约需要 20 分钟,生产环境大约需要 4 分钟,当然这取决于应用程序设置和服务器硬件。您可以将其放入rake task或某些后台工作人员。