首先说明几点:

  1. excel格式的文件最大支持100万的数据,所以不考虑使用excel格式
  2. laravel的toArray()方法有内存泄露,所以大量数据导出不能使用.
  3. 当然要使用chunk方法查询数据,然后写到文件中

关于toArray()方法内存泄露排查

chunk()方法的代码块如下(chunk中按理是不用unset的,会自动释放):

 $ormQuery->chunk(1000, function ($data) use (&$firstWrite, $fp) {
Log::info("开始:".memory_get_usage());
$data = $data->toArray();
Log::info("结束:".memory_get_usage());
unset($data);
Log::info("usnet 结束:".memory_get_usage());
});

日志

从下往上看

Screen Shot 2017-04-01 at 4.16.38 PM.png

通过日志我们可以分析得出:
在将一个“组块”的 Eloquent 模型转为数组的时候$data = $data->toArray();内存增加了很多.最后unset的时候又没有释放回初始值.实际上chunk中是不需要unset释放的.

解决

使用
DB::table("xxx")->->orderBy(xx)->chunk(xx);方式查询数据,查询结果在使用$data = json_decode(json_encode($data), true);转换成数组,每次chunk执行进去,内存都是一样的,内部也不需要unset.

大数据导出最后做的方案

因为数据量大,所以我的做法是,小量数据导出就直接发送给用户.大数据导出,走队列任务,然后做一个报表管理,用户可以查看进度和完成后下载.

在浏览器中直接返回文件和后台写入文件

函数基本使用

$fp = fopen("文件路径/文件名", "a");  //a表示追加模式
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF)); // 添加 BOM,不然excel打开csv是乱码
在chunk的闭包中写数据: fputcsv($fp, $array);
fclose($fp);

在队列中导出

 $fp = fopen(storage_path('app/public/exports')."/".$report->name, "a");
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF)); // 添加 BOM
$firstWrite = true;
$query = $expoter->customQuery($query);
$query->orderBy($tableName.".id")->chunk(1000, function ($data) use (&$firstWrite, $fp, $expoter) {
$data = json_decode(json_encode($data), true); $data = $expoter->customData($data);
//有一些列总是不导出,如icon,image,images
$data = ExportUtils::removeInvalids($data);
//写列名
if ($firstWrite) {
$columnNames = [];
//获取列名
foreach ($data[0] as $key => $value) {
$columnNames[] = admin_translate($key, "coupon");
}
fputcsv($fp, $columnNames);
$firstWrite = false;
}
foreach ($data as $item) {
fputcsv($fp, $item);
}
}); fclose($fp);

在浏览器中返回数据

 $response = new StreamedResponse(null, 200, [
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="'.$fileName.'"',
]);
$response->setCallback(function () use ($query, $tableName) {
$out = fopen('php://output', 'w');
fwrite($out, chr(0xEF).chr(0xBB).chr(0xBF)); // 添加 BOM $firstWrite = true; $query = $this->customQuery($query); $query->orderBy($tableName.".id")->chunk(500, function ($data) use (&$firstWrite, $out) { $data = json_decode(json_encode($data), true); $data = $this->customData($data);
//有一些列总是不导出,如icon,image,images
$data = ExportUtils::removeInvalids($data);
//写列名
if ($firstWrite) {
$columnNames = [];
//获取列名
foreach ($data[0] as $key => $value) {
$columnNames[] = admin_translate($key, "coupon");
}
fputcsv($out, $columnNames);
$firstWrite = false;
}
foreach ($data as $item) {
fputcsv($out, $item);
}
}); fclose($out);
});
$response->send();

laravel实现大数据csv导出的更多相关文章

  1. php使用fputcsv进行大数据的导出

    为了实验大数据的导出,我们这里先自已创建一张大表,表结构如下: CREATE TABLE `tb_users` ( `id` int(11) unsigned NOT NULL AUTO_INCREM ...

  2. PHPExcel 大数据的导出

    PHPExcel 是一个php语言读取导出数据.导入生成Excel的类库,使用起来非常方便,但有时会遇到以些问题,比如导出的数据超时,内存溢出等. 下面我们来说说这些问题和解决办法. PHPExcel ...

  3. ajax大数据排队导出+进度条

    描述 :我们现在有很多数据,分表存放,现在需要有精度条的导出.最后面有完整源码. 效果图:

  4. poi 操作Excel 以及大数据量导出

    maven 依赖 (版本必须一致,否则使用SXSSFworkbook 时程序会报错) <dependency> <groupId>org.apache.poi</grou ...

  5. EasyPoi大数据导入导出百万级实例

    EasyPoi介绍: 利用注解的方式简化了Excel.Word.PDF等格式的导入导出,而且是百万级数据的导入导出.EasyPoi官方网址:EasyPoi教程_V1.0 (mydoc.io).下面我写 ...

  6. SQL Server 使用bcp进行大数据量导出导入

    转载:http://www.cnblogs.com/gaizai/archive/2010/04/17/1714389.html SQL Server的导出导入方式有: 在SQL Server中提供了 ...

  7. Export大数据量导出和打包

    项目需求 ​ 导出生成大批量数据的文件,一个Excel中最多存有五十万条数据,查询多余五十万的数据写多个Excel中.导出完成是生成的多个Excel文件打包压缩成zip,而后更新导出记录中的压缩文件路 ...

  8. 使用内存映射文件MMF实现大数据量导出时的内存优化

    前言 导出功能几乎是所有应用系统必不可少功能,今天我们来谈一谈,如何使用内存映射文件MMF进行内存优化,本文重点介绍使用方法,相关原理可以参考文末的连接 实现 我们以单次导出一个excel举例(csv ...

  9. 大数据Excel导出方案

    static void Main(string[] args) { Excel.Application app = new Excel.Application(); Excel._Workbook r ...

  10. 记录一笔关于PHPEXCEL导出大数据超时和内存溢出的问题

    通过查阅资料可以找到PHPEXCEL本身已经有通过缓存来处理大数据的导出了.但是昨晚一直没有成功,这可捉急了.最后想来想去就替换了phpExcel的版本了.最后就成功了.话不多说,代码附上 <? ...

随机推荐

  1. MySQL数据库本地连接失败

    前提: MySQL5.5 + SQLyog软件,从安装开始一直可以正常使用 现象: 用SQLyog软件登录,显示本地连接失败.怀疑可能是MySQL服务没有开启,结果发现服务里面找不到MySQL这一条( ...

  2. net-snmp 自定义OID利用脚本获取值

    两种办法: 1)pass方式 /etc/snmp/snmpd.conf 写脚本 脚本需要注意:要连续输出三行:1.OID 2.类型 3.值 如果不按照这个规定,直接输出值,将会报错. 检查 第二种方法 ...

  3. 2003031126-石升福-python数据分析第四周作业-第二次作业

    项目 matplotlib 博客名称 2003031126-石升福-Python数据分析第四周作业 班级链接 20级数据班 作业链接 第二次作业 要求 每道题要有题目,代码(使用插入代码,不会插入代码 ...

  4. hdu:最大点权(强连通分量kosaraju)

    Problem Description给定一个有向图,每个点ii有点权a_ia​i​​,请对于每个点ii,找到ii能到达的点中点权的最大值(包括ii点). Input第一行包含一个正整数T(1\leq ...

  5. logrotate linux 系统日志管理

    logrotatelogrotate简介 logrorare一定程度上可以简化对会生成大量日志文件的系统的管理.logrotate可以实现自动轮替.删除.压缩和mail日志的功能. 执行命令logro ...

  6. 功能测试--APP专项

    APP测试重点 APP测试与web测试的区别 APP测试常见问题 APP日志分析 APP压力稳定性测试

  7. 通过Rdp实现连接远程桌面

    unit UnitMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Fo ...

  8. Tensorflow learning notebook

    How does tensorflow work 原著blog https://jacobbuckman.com/#posts

  9. linux 修改文件内容命令

    1.进入文件:vim 文件名 eg #vim /etc/httpd/httpd.conf 2.查找待修改内容位置 : (1)shift+":",使文件变成可查询状态 (2)输入 / ...

  10. 【Linux 中断】红外接收器设备驱动

    一.概述 现在很多家电都使用了红外,而智能家居的诞生,连音响都带了红外遥控功能.为了解决家里遥控器比较多的情况,多数手机都支持了红外功能,这和以前的万能遥控器一样.这里主要记录红外接收的驱动,当然明白 ...