【问题标题】:updateOrCreate() >100k recordsupdateOrCreate() >100k 记录
【发布时间】:2020-04-22 09:52:22
【问题描述】:

我有一个功能,用户可以上传CSV 文件(列表),以在DB 中存储/更新电子邮件:

//load CSV
$records = file($request->file('list'), FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

//prepare for mass insert
foreach ($records as $email) {
    $updateOrCreate[] = [
        'email' => $email
    ];
}

DB::beginTransaction();

try {

    $toKeep = [];

    //run a loop to cjeck if email already exists if not create
    foreach ($updateOrCreate as $record) {

        $email = List::updateOrCreate([
            'email' => $record['email']
        ], $record);

        $toKeep[] = $email->id;

    }

    //delete all records that where no in new CSV
    if (count($toKeep)) {
        List::whereNotIn("id", $toKeep)->delete();
    }

} catch (Exception $e) {

    DB::rollBack();

    return response()->json([
        'message' => $e->getMessage()
    ], 422);
}

DB::commit();

这个解决方案很好用,最多几千条记录,如果尝试上传 50k 或更多,速度很慢,我明白为什么很慢(查询每条记录选择/更新或插入):

foreach ($updateOrCreate as $record) {

    $email = List::updateOrCreate([
       'email' => $record['email']
    ], $record);

    $toKeep[] = $email->id;     
}

对于插入,我使用了原始的 pg_copy_from,效果很好且速度很快

$result = pg_copy_from($dbconn, 'lists (email)', $records, ',');

所以我在徘徊是否有类似的检查记录是否不在列表中删除或添加新的,更有效/更快的方式,也许像pg_copy_from

【问题讨论】:

    标签: php sql laravel postgresql


    【解决方案1】:

    据我所知,您正在以 CSV 的 AJAX 上传方式执行此操作,并且您可能在处理时遇到了超时。一个简单的事实是,有了这么多的记录和您正在采取的行动,这将需要很长时间。

    我建议重新考虑您的方法,例如:

    • 用户上传文件
    • 文件存储在存储中的某处
    • 设置了一个新的排队作业来处理 CSV
    • 已发送用户响应
    • 队列作业在后端执行和处理(没有超时,但注意内存不足问题)
    • 完成后,用户会收到有关流程的通知(广播、电子邮件)

    只要您管理用户期望,这应该可以工作。

    【讨论】:

      猜你喜欢
      • 2022-01-16
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-29
      • 2013-04-12
      相关资源
      最近更新 更多