当所有记录不同时,如何使用全部更新?

Mar*_*kus 14 activerecord bulk ruby-on-rails-3 update-all

update_all如果我想更新包含各种不同值的300,000条记录的列,我该如何使用?

我想做的是:

Model.update_all(:column => [2,33,94,32]).where(:id => [22974,22975,22976,22977]) 
Run Code Online (Sandbox Code Playgroud)

但不幸的是,这不起作用,而且对于300,000个条目来说更糟糕.

our*_*nos 16

来自ActiveRecord#update文档:

people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
Person.update(people.keys, people.values)
Run Code Online (Sandbox Code Playgroud)

所以在你的情况下:

updates = {22974 => {column: 2}, 22975 => {column: 33}, 22976 => {column: 94}, 22977 => {column: 32}}
Model.update(updates.keys, updates.values)
Run Code Online (Sandbox Code Playgroud)

编辑:刚看了一下源代码,这也产生了n个 SQL查询......所以可能不是最好的解决方案


san*_*e89 6

这是我2020年的答案:

  1. 得票最多的答案是错误的;正如作者自己所说,它将触发nSQL 查询,每一行一个。

  2. 第二个获得最多支持的答案建议 gem“activerecord-import”,这是要走的路。然而,它是通过实例化 ActiveRecord 模型来实现的,如果您从事这样的业务,您可能正在寻找极致的性能(无论如何,这就是我们的情况)。

这就是我们所做的。首先,构建一个哈希数组,每个哈希包含id要更新的记录和任何其他字段。

例如:

records = [{ id: 1, name: 'Bob' }, { id: 2, name: 'Wilson' },...]

然后你像这样调用 gem:

YourModelName.import(records, on_duplicate_key_update: [:name, :other_columns_whose_keys_are_present_in_the_hash], validate: false, timestamps: false)
Run Code Online (Sandbox Code Playgroud)

解释:

  • on_duplicate_key_update这意味着,如果数据库在主键上发现冲突(并且在每一行上都会发生冲突,因为我们正在讨论更新现有记录),它不会失败,而是更新您在该数组上传递的列。

  • 如果您不这样做validate false(默认值为 true),它将尝试为每一行实例化一个新的模型实例,并且可能会因验证而失败(因为您的哈希仅包含部分信息)。

  • timestamp false也是可选的,但很高兴知道它在那里。


pdu*_*uey 5

你的问题的简短回答是,你不能。

The point of update_all is to assign the same value to the column for all records (matching the condition if provided). The reason that is useful is that it does it in a single SQL statement.

I agree with Shime's answer for correctness. Although that will generate n SQL calls. So, maybe there is something more to your problem you're not telling us. Perhaps you can iterate over each possible value, calling update_all for the objects that should get updated with that value. Then it's a matter of either building the appropriate hash, or, even better, if the condition is based on something in the Model itself, you can pass the condition to update_all.


Yur*_*ich 5

我发现这样做的唯一方法是使用更新的值生成INSERT INTO请求。我为此使用宝石“ activerecord-import”

例如,我有一个带有val值的表

+--------+--------------+---------+------------+-----+-------------------------+-------------------------+
| pkey   | id           | site_id | feature_id | val | created_at              | updated_at              |
+--------+--------------+---------+------------+-----+-------------------------+-------------------------+
| 1      |              | 125     | 7          | 88  | 2016-01-27 10:25:45 UTC | 2016-02-05 11:18:14 UTC |
| 111765 | 0001-0000024 | 125     | 7          | 86  | 2016-01-27 11:33:22 UTC | 2016-02-05 11:18:14 UTC |
| 111766 | 0001-0000062 | 125     | 7          | 15  | 2016-01-27 11:33:22 UTC | 2016-02-05 11:18:14 UTC |
| 111767 | 0001-0000079 | 125     | 7          | 19  | 2016-01-27 11:33:22 UTC | 2016-02-05 11:18:14 UTC |
| 111768 | 0001-0000086 | 125     | 7          | 33  | 2016-01-27 11:33:22 UTC | 2016-02-05 11:18:14 UTC |
+--------+--------------+---------+------------+-----+-------------------------+-------------------------+
Run Code Online (Sandbox Code Playgroud)

选择记录

products = CustomProduct.limit(5)
Run Code Online (Sandbox Code Playgroud)

根据需要更新记录

products.each_with_index{|p, i| p.val = i}
Run Code Online (Sandbox Code Playgroud)

将记录保存在单个请求中

CustomProduct.import products.to_a, :on_duplicate_key_update => [:val]
Run Code Online (Sandbox Code Playgroud)

您所有的记录将在单个请求中更新。请查看gem“ activerecord-import”文档以获取更多详细信息。

+--------+--------------+---------+------------+-----+-------------------------+-------------------------+
| pkey   | id           | site_id | feature_id | val | created_at              | updated_at              |
+--------+--------------+---------+------------+-----+-------------------------+-------------------------+
| 1      |              | 125     | 7          | 0   | 2016-01-27 10:25:45 UTC | 2016-02-05 11:19:49 UTC |
| 111765 | 0001-0000024 | 125     | 7          | 1   | 2016-01-27 11:33:22 UTC | 2016-02-05 11:19:49 UTC |
| 111766 | 0001-0000062 | 125     | 7          | 2   | 2016-01-27 11:33:22 UTC | 2016-02-05 11:19:49 UTC |
| 111767 | 0001-0000079 | 125     | 7          | 3   | 2016-01-27 11:33:22 UTC | 2016-02-05 11:19:49 UTC |
| 111768 | 0001-0000086 | 125     | 7          | 4   | 2016-01-27 11:33:22 UTC | 2016-02-05 11:19:49 UTC |
+--------+--------------+---------+------------+-----+-------------------------+-------------------------+
Run Code Online (Sandbox Code Playgroud)