如何在给定键和值数组的情况下有效地在 Eloquent 中进行大规模更新

Posted

技术标签:

【中文标题】如何在给定键和值数组的情况下有效地在 Eloquent 中进行大规模更新【英文标题】:How to mass update in Eloquent given an array of keys and values efficiently 【发布时间】:2021-12-27 12:21:36 【问题描述】:

我有一个非常大(数百万行)的数据库表,我需要将来自第 3 方的一些缺失数据添加到每一行。

数据源有一个“参考键”,这是我映射到表中正确项目的唯一方法

每行需要更新 1 个数字

我可以遍历第 3 方数据源并使用唯一标识符对每一行执行雄辩的更新,但从我的测试来看这非常慢:

Orders
  id,  reference_key,  new_value
  int, string,         double(8,2)

foreach ($xml as $row) 
    Order::where('reference_key', $reference_key)
        ->update('new_value', (float)$row->new_value);


有没有更有效的方法可以做到这一点?

【问题讨论】:

【参考方案1】:

Eloquent 在管理复杂的关系、连接、预先加载的模型等方面非常强大……但是这种抽象有性能成本。每个模型都必须被创建、填充和保存,其中包含大量您在这个精确用例中不需要的功能。

在编辑数千甚至数百万条记录时,使用 Eloquent 模型效率非常低。相反,您可以使用 laravel 查询构建器或原始 SQL 语句。

我会推荐这种方法:

$table = Db::table('orders');
foreach ($xml as $row) 
    $table->where('reference_key', $reference_key)
        ->update('new_value', (float)$row->new_value);

但你也可以这样做:

foreach ($xml as $row) 
    DB::statement('UPDATE orders SET new_value=? WHERE reference_key=?', 
    [(float)$row->new_value, $reference_key]);

它会显着减少您的执行时间,但数百万 XML 行的循环仍然需要很长时间。

【讨论】:

对 eloquent 构建器的 update 调用不会填充模型,它通过查询构建器运行 update 查询,但添加了 updated_at 我在没有任何 SQL 的情况下进行了测试,XML 处理时间不到一秒。我最终将大量原始 SQL 更新链接在一起并分块处理它们,在我的测试中它已经足够快了!从一周缩短到几个小时 :) 与您的第二种方法基本相同,但一次使用未准备好的多个语句。除了这个任务之外我永远不会做的事情。【参考方案2】:

我会像这样做一次更新语句:

UPDATE OrderTable
INNER JOIN table_to_fill ON OrderTable.refkey = table_to_fill.refkey
SET OrderTable.value = table_to_fill.value

【讨论】:

以上是关于如何在给定键和值数组的情况下有效地在 Eloquent 中进行大规模更新的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Bash 中间接获取关联数组的键和值?

如何将 JSON 属性值转换为键和值数组

如何在不使用循环的情况下在 PHP 中向多维添加新的键和值......?

如何从数组中的对象添加新的键和值?

如何将对象数组操作为不同的键和值? [复制]

如何获取与php数组中的键和值相关的所有数组值