【问题标题】:How to mass update in Eloquent given an array of keys and values efficiently如何在给定键和值数组的情况下有效地在 Eloquent 中进行大规模更新
【发布时间】: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);
}

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

【问题讨论】:

    标签: mysql laravel eloquent


    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-27
      • 1970-01-01
      • 1970-01-01
      • 2023-01-13
      相关资源
      最近更新 更多