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

使用Maatwebsite Laravel Excel 3.1导出超10k数据遇超时问题

Laravel Excel 3.1 大数据导出超时问题排查与解决

问题描述

  • 使用Maatwebsite Laravel Excel 3.1包导出数据库中超过10000条数据到Excel,数据量少于10k时运行正常
  • 已在导出类中实现ShouldQueue、WithCustomChunkSize进行分块处理,但仍出现超时错误
  • 当前PHP内存限制为512M

现有导出类代码

namespace App\Exports;

use App\Events\Download\DownloadComplete;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Support\Arr;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithCustomChunkSize;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Events\AfterSheet;
use App\Traits\ReportDownloadTrait;
use Throwable;
use App\PreDownloadData;

class ReportExport implements FromQuery, WithHeadings, ShouldAutoSize, Responsable, WithEvents, WithTitle, WithMapping, WithCustomChunkSize, ShouldQueue
{
    use Exportable, ReportDownloadTrait;

    protected array $headings, $inputs;
    protected int $download_id;

    public $fileName = "report_download.xlsx";
    public $timeout = 1200; // 5 hour
    public $tries = 3;

    public function query()
    {
        return DownloadData::whereDownloadId($this->download_id)->whereNotNull('row');
    }

    public function map($data): array
    {
        return $data->row;
    }

    public function batchSize(): int
    {
        return 200;
    }

    public function chunkSize(): int
    {
        return 200;
    }

    public function headings(): array
    {
      [];
    }
}

问题排查与优化方案

1. 修正模型引用错误

代码中引入了PreDownloadData模型,但query()方法调用的是不存在的DownloadData,这会直接导致查询异常,先修正:

public function query()
{
    return PreDownloadData::whereDownloadId($this->download_id)->whereNotNull('row');
}

2. 匹配队列Worker超时配置

虽然导出类设置了$timeout = 1200,但Laravel队列Worker默认超时为60秒,会提前终止进程。需要同步调整Worker超时:

  • 启动Worker时指定超时:
php artisan queue:work --timeout=1200
  • 或者在config/queue.php对应队列连接的配置中设置timeout为1200。

3. 调小分块处理大小

当前chunkSize和batchSize设为200,对于大数据量来说单次处理压力仍较大,建议调小到100或50:

public function chunkSize(): int
{
    return 100;
}

public function batchSize(): int
{
    return 100;
}

4. 关闭自动列宽计算

ShouldAutoSize会为每列计算最优宽度,大数据量下该操作耗时极高,建议移除该接口实现,手动指定列宽:

// 移除 ShouldAutoSize 接口,修改后的类声明:
class ReportExport implements FromQuery, WithHeadings, Responsable, WithEvents, WithTitle, WithMapping, WithCustomChunkSize, ShouldQueue

如果需要固定列宽,在WithEvents中配置:

public function registerEvents(): array
{
    return [
        AfterSheet::class => function(AfterSheet $event) {
            // 设置A到Z列宽度为15
            $event->sheet->getDelegate()->getColumnDimension('A:Z')->setWidth(15);
        },
    ];
}

5. 内存与查询优化

  • 禁用模型事件:临时关闭模型的事件监听,减少额外开销:
public function query()
{
    PreDownloadData::flushEventListeners();
    return PreDownloadData::whereDownloadId($this->download_id)->whereNotNull('row');
}
  • 只查询必要字段:如果row是大字段或JSON,确认是否需要全部导出,避免加载冗余数据。

6. 确认队列驱动为异步

如果使用sync驱动,队列会同步执行,无法实现后台异步处理,必须切换到redis、database等异步驱动。

7. 简化map方法逻辑

确保map方法仅做必要的数据转换,避免在该方法中执行复杂计算或额外查询。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 20:22:42