如何在给定键和值数组的情况下有效地在 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 中进行大规模更新的主要内容,如果未能解决你的问题,请参考以下文章