探讨一下大数据量的导出Excel 方案
导出的要求:
- 数据量可能最大10-20万不止
- 主表数据字段也很多
- 不能限制导出的日期和导出数量限制
- 低内存,不能把内存搞崩
目前的方案:
采用 分批次 ,一个批次5000 条, 导出成excel, 最后再把 这一批次的excel 压缩成 zip 格式提供给客户下载, 完成整体需求 扩展用的是fast-excel 压缩扩展用的是自己二次封装的:flttgo/easy-zipper 因为原作者不维护了,但是我们PHP 版本比较低,所以进行了二次处理
有好的方案欢迎留言讨论,目前不知道还有啥方案,其他语言的方案暂且不考虑,优先PHP ,其他语言对于这个问题,有同样的问题和难点,无论怎么异步,内存这块避免不掉
我的方案部分核心代码
生成批次队列的代码
$jobs = []; $chunks = ApplyRisk::getListQuery(ApplyRiskFilter::apply($params, 'afterLoan')) ->select(['apply_risk_id']) ->chunkById(5000, function ($rows, $page) use (&$jobs) { $ids = $rows->pluck('apply_risk_id')->toArray(); $jobs[] = new AfterLoanExportBatchJob($this->task, LazyCollection::make($ids), $page); }); unset($chunks); $taskId = $this->task->id; Bus::batch($jobs) // 所有任务完成才执行的回调 ->finally(function (Batch $batch) use ($taskId) { if ($batch->finished()) { dispatch(new AfterLoanExportFinishJob($taskId)); } })->dispatch(); unset($jobs); 批次队列导出格式的数据采用 yield 生成, 字段用filed 替代
public function genertateLazyData($chunks) { /** @var \Illuminate\Support\LazyCollection $chunk */ yield from ApplyRisk::select([ 'field' ])->whereIn('apply_risk_id', $chunks)->lazy()->each(function ($row) { yield $this->transform->afterLoan($row); }); } 导出excel 代码
$dir = storage_path($this->task->hash_id); if (!File::exists($dir)) { if (! @mkdir($dir, 0755, true) && ! is_dir($dir)) { throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir)); } } $fileName = $dir.'/'.$this->task->title.'-'.$this->index.'.xlsx'; //数据准备完毕,开始导出 FastExcel::data($this->genertateLazyData($this->riskIds))->export($fileName); 上面是我这次处理的核心逻辑


关于 LearnKu
推荐文章: