Laravel-Excel 2 大批量Excel数据入库提速方法咨询
优化Laravel-Excel 2处理百万级Excel导入的方案
针对你遇到的140万行大型Excel导入性能瓶颈,我分享几个亲测有效的优化思路,以及对你已验证分块方案的补充优化:
核心优化建议
- 批量插入替代单条插入:原来循环里每次
insert单条数据,会频繁触发数据库交互,性能极低。攒一批数据(比如100-500条)再批量插入,能大幅减少数据库连接次数,这是提升速度的核心。 - 分块处理避免内存溢出:把大数据集拆成小chunk,既控制单次插入的数据量,也避免一次性加载全量数据导致内存耗尽——你已经用了这个方案,效果确实明显。
- 流式读取(内存友好型方案):不要一次性把整个Excel转成数组,用Laravel-Excel的
each方法逐行读取处理,边读边攒批量数据,内存占用会非常低,完美适配百万级数据。 - 数据库层面优化:
- 保持事务包裹批量操作(你已经在做了),避免部分插入失败导致数据不一致;
- 临时关闭外键检查(如果表有外键约束):
DB::statement('SET FOREIGN_KEY_CHECKS=0;'),插入完成后再开启; - 禁用自动提交:
DB::statement('SET AUTOCOMMIT=0;'),事务结束后恢复默认设置。
- 多工作表分批处理:如果有多个工作表,循环遍历每个工作表单独处理,不要一次性加载所有工作表的数据。
你验证有效的分块处理代码(格式化版)
$data = Excel::selectSheetsByIndex(0)->load($file, function($reader) {})->get()->toArray(); DB::beginTransaction(); try { $bulk_data = []; foreach ($data as $key => $value) { $med = trim($value["med"]); $serial = trim($value["nro.seriemedidor"]); $bulk_data[] = ["med" => $med,"serial_number" => $serial]; } $collection = collect($bulk_data); $chunks = $collection->chunk(100); // 按100条分块处理 foreach($chunks as $chunk) { DB::table('medidores')->insert($chunk->toArray()); } DB::commit(); } catch (\Exception $e) { DB::rollback(); return redirect()->route('myroute')->withErrors("导入失败:" . $e->getMessage()); }
更适配百万级数据的流式读取方案
如果140万行数据一次性转成数组仍会出现内存溢出,试试流式逐行处理,不需要把全量数据加载到内存:
DB::beginTransaction(); try { $bulk_data = []; $chunkSize = 100; // 每100条执行一次批量插入 Excel::selectSheetsByIndex(0)->load($file, function($reader) use (&$bulk_data, $chunkSize) { // 逐行遍历Excel数据 $reader->each(function($row) use (&$bulk_data, $chunkSize) { $med = trim($row->med); $serial = trim($row->get('nro.seriemedidor')); $bulk_data[] = ["med" => $med, "serial_number" => $serial]; // 达到设定的批量数就插入并清空数组 if (count($bulk_data) >= $chunkSize) { DB::table('medidores')->insert($bulk_data); $bulk_data = []; } }); }); // 处理最后一批不足批量数的数据 if (!empty($bulk_data)) { DB::table('medidores')->insert($bulk_data); } DB::commit(); return redirect()->route('myroute')->withSuccess("导入成功!"); } catch (\Exception $e) { DB::rollback(); return redirect()->route('myroute')->withErrors("导入失败:" . $e->getMessage()); }
这个方案的优势是内存占用极低,不管Excel有多少行,都不会因为加载全量数据导致内存溢出,是超大型文件导入的最优解。
内容的提问来源于stack exchange,提问作者pmiranda
相关产品推荐
相关产品推荐

