You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel批量插入25万条数据遇PHP超时问题(多租户+队列)

问题

使用Laravel Eloquent向MySQL插入25万条记录时遭遇PHP执行超时,已尝试Laravel Queue但问题依旧。当前环境约束:

  • 前端:Angular
  • 多租户:基于Tenancy for Laravel实现

已用代码

任务文件代码

class MedicineData implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Batchable;

    public $data;

    public function __construct($data)
    {
        $this->data = $data;
    }

    public function handle(): void
    {
        foreach ($this->data as $key => $value) {
            $medicine = new MedicineName();
            $medicine->name = $value['name'];
            $medicine->save();
        }
    }
}

控制器文件代码

$chunks = array_chunk($data, 500);
$batch = Bus::batch([])->dispatch();

foreach ($chunks as $key => $value) {
    $batch->add(new MedicineData($value));
}
解决方案
  • 替换循环单条保存为Eloquent批量插入
    队列任务里循环调用save()会生成500条独立SQL,执行效率极低,这才是超时的核心原因。改成批量插入,单条SQL完成500条数据插入:
public function handle(): void
{
    $insertData = collect($this->data)->map(fn($item) => ['name' => $item['name']])->toArray();
    MedicineName::insert($insertData);
}
  • 调整队列Worker的超时配置
    队列Worker自身有执行时间限制,默认可能过短。在config/queue.php对应驱动下修改timeout参数,或者启动Worker时用命令行参数覆盖:
// config/queue.php 中database驱动配置示例
'database' => [
    'driver' => 'database',
    'table' => 'jobs',
    'queue' => 'default',
    'retry_after' => 90,
    'timeout' => 60, // 按需调整,单位秒
],

启动命令:

php artisan queue:work --timeout=60
  • 缩小Chunk尺寸
    如果500条批量插入仍超时,把array_chunk的第二个参数降到200或100,减少单任务处理量,降低单任务执行时间。

  • 确保队列任务中多租户上下文正确
    多租户环境下,队列执行时必须切换到对应租户的上下文,否则会导致数据库连接异常或性能损耗。可以在任务构造时传入租户ID,在handle方法中初始化租户:

// 修改任务类
public $data;
public $tenantId;

public function __construct($data, $tenantId)
{
    $this->data = $data;
    $this->tenantId = $tenantId;
}

public function handle(): void
{
    tenancy()->initialize(Tenant::find($this->tenantId));
    
    $insertData = collect($this->data)->map(fn($item) => ['name' => $item['name']])->toArray();
    MedicineName::insert($insertData);
}

控制器中传参:

$tenantId = tenant()->id; // 获取当前租户ID
$chunks = array_chunk($data, 500);
$batch = Bus::batch([])->dispatch();

foreach ($chunks as $chunk) {
    $batch->add(new MedicineData($chunk, $tenantId));
}
  • 临时关闭模型事件
    如果MedicineName模型有created、saving等事件监听,批量插入时会触发数百次事件,增加执行时间。可以临时关闭:
public function handle(): void
{
    MedicineName::withoutEvents(function () {
        $insertData = collect($this->data)->map(fn($item) => ['name' => $item['name']])->toArray();
        MedicineName::insert($insertData);
    });
}

内容的提问来源于stack exchange,提问作者Rizwan Ansari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 02:07:46