不能用 appendRow 循环写入,因 Excel::create() 在 Laravel 10+ 和 maatwebsite/excel 4.x 中已不存在,且 appendRow() 累积内存、不支持流式响应、无法中途 GC,5 万行即超 512MB 内存。

直接用 Excel::create() 或循环调用 appendRow() 会把整张表加载进内存,10万行就大概率 OOM ——这不是导出,是给自己埋雷。
为什么不能用 appendRow 循环写入
老教程里常见的 Excel::create() + appendRow() 模式,在 Laravel 10+ 和 maatwebsite/excel 4.x 中已完全不可用:Excel::create() 类根本不存在,调用即报错 Class "Excel" not found。即使降级到 3.x,appendRow() 本质是累积写入内存中的 PHPExcel 对象,每行都增加对象引用和样式缓存,内存增长非线性。导出 5 万行用户数据时,实际内存占用常超 512MB,远超默认配置。
- 不支持流式响应,必须等全部写完才发 HTTP body
- 无法中途 gc,PHP 引用计数残留严重
- 导出过程中若数据库连接超时或网络中断,整个请求失败且无恢复点
FromQuery + WithChunkReading 是正解
真正能撑住 10 万+ 行的方案,是让数据库按块吐数据、Laravel-Excel 按块转 Excel 行、边生成边推给浏览器。核心是两个接口:实现 FromQuery 返回 Builder,再加 WithChunkReading 控制分片大小。
罗老师数据不上传 Excel VBA 本地处理专家 是一个面向企业隐私数据、本地化数据处理和 Excel 自动化的新手陪跑 skill。它不会要求用户上传原始表格,而是引导用户只提供表名、字段、规则和脱敏样例,再生成可复制到 Excel 里运行的 VBA 代码,帮助完成清洗、匹配、筛选、汇总、拆分和报表生成等任务。
-
query()方法里只返回User::query(),绝不能调->get()或->cursor() -
chunkSize()设为 1000~2000,太小增加 I/O 次数,太大仍吃内存 - 字段映射必须在
map()回调里做,但注意:Eloquent 关系(如$user->profile)拿不到,得提前select()或join() - 中文字段乱码?不是编码问题,是字体没设 —— 在导出类里加
WithStyles接口,用['font' => ['name' => '微软雅黑']]
控制器里传参别丢,request() 在 generator 里已失效
导出类被 Excel::download() 调用时,Laravel 的请求上下文早已销毁。request()->input('status') 会返回 null,导致查全表而非筛选结果——这是线上最隐蔽的坑之一。
- 所有筛选条件必须在控制器里拼好,再传进 Export 类构造函数
- 别在
query()里写request()->xxx,哪怕它“看起来能跑通” - 导出类应接收一个已构建好的
Builder实例,比如new UsersExport($query) - 如果要用
FromCollection,也得确保collection()返回的是Illuminate\Support\Collection实例,不是数组 —— 写return new Collection($users),别写return $users->toArray()
FastExcel 是更轻量的替代选择
如果你不需要复杂样式、多 sheet、公式或图片,rap2hpoutre/fast-excel 的流式导出更直接:它基于 Spout,天生不加载整表,100 万行内存稳定在 10MB 左右。
- 安装后无需配置:
composer require rap2hpoutre/fast-excel - 导出只要一行:
(new FastExcel(User::cursor()))->export('users.xlsx')—— 注意用cursor(),不是get() - 自定义列名用闭包:
(new FastExcel(User::cursor()))->export('users.xlsx', fn($u) => ['ID' => $u->id, '姓名' => $u->name]) - 它不处理样式和格式,但胜在快、稳、无依赖;真要加样式,还是得回 Laravel-Excel
流式导出真正的难点不在代码行数,而在数据边界控制:chunk 大小、GC 触发时机、关联字段预加载范围、HTTP 缓冲区刷新节奏——这些参数没有银弹,得结合你服务器的内存配额和 MySQL 的 sort_buffer_size 实测调整。

















