php 用csv文件导出大量数据初方案
背景:接手的项目中支持导出一批数据,全数量在50W左右。在接手的时候看代码是直接一次查询MySQL获得数据,然后用header函数直接写入csv,用户开始导出则自动下载。但是,在全导出的时候,功能出现了BUG问题。
1.数据量大导致PHP处理脚本运行时间,超过默认限制。
2.数据量过大,导致内存溢出,流程中止。
初版解决方案:
1.通过函数set_time_limit(0); 取消执行时间限制(在导出的函数入口设置,这是合理的,导出的数据量过大了)
2.关于数据过大,内存溢出的解决办法,开始是想到了php动态变量(先由sql语句获得总记录数,然后每2W条切分,查询2w条数据存入一个变量)
- $total_export_count = $db->getOne("select count(1) from ($sql) t2");
- for ($i=0;$i<intval($total_export_count/20000)+1;$i++){
- $export_data = "exportdata".$i;
- $$export_data = $db->getAll($sql." limit ".strval($i*20000).",20000");
- }
然后通过相应的代码取出变量的信息,echo到csv文件中,这种方式在本地测试的时候是通过的,但在服务器上依旧会内存溢出。
- header ( "Content-type:application/vnd.ms-excel" );
- header ( "Content-Disposition:filename=" . iconv ( "UTF-8", "GB18030", "查询用户列表" ) . ".csv" );
- $out = $column_name;
- echo iconv ( "UTF-8", "GB18030", $out );
- for ($i=0;$i<intval($total_export_count/20000)+1;$i++){
- $dynamic_name = "exportdata".$i;
- foreach ( $$dynamic_name as $key => $item ) {
- echo iconv ( "UTF-8", "GB18030", "\n".implode(',',$item) );
- }
- // 将已经写到csv中的数据存储变量销毁,释放内存占用
- unset($$dynamic_name);
- }
- exit ();
因为上面的方法在服务器上没有通过,所以只能将分割数据量的操作放到写文件的流程中,相比上面的思路这种会慢一些。
- header ( "Content-type:application/vnd.ms-excel" );
- header ( "Content-Disposition:filename=" . iconv ( "UTF-8", "GB18030", "查询用户列表" ) . ".csv" );
- $out = $column_name;
- echo iconv ( "UTF-8", "GB18030", $out );
- $pre_count = 20000;
- for ($i=0;$i<intval($total_export_count/$pre_count)+1;$i++){
- $export_data = $db->getAll($sql." limit ".strval($i*$pre_count).",{$pre_count}");
- foreach ( $export_data as $key => $item ) {
- echo iconv ( "UTF-8", "GB18030", "\n".implode(',',$item) );
- }
- // 将已经写到csv中的数据存储变量销毁,释放内存占用
- unset($export_data);
- }
- exit ();
经测试之后是可行的,服务器上也可以导出,就是时间会慢一些,而且会是一直下载状态。
关于这个场景整理了一些资料:
1.csv文件的条数是好像没有限制的,可以一直写(网上的博文里面看的,没证实过)
2.excel 2010版本以上,是可以读取100多W行数据的(验证过,新建一个excel,ctrl+下箭头 到文件末尾可以看到行数)
理想的解决方案(没有具体实施,想的)
1.数据分割肯定是必须的步骤,防止内存溢出。
2.将分割后的数据写入到一个excel或者一个csv文件中,被分割了多少次,写多少个文件。这样可以防止达到文件行数的最大限制。
3.将2中写的文件进行压缩处理,压缩成一个压缩包,然后进行自动下载。
补充:
在上面的方案正式运行的时候发现导出的数据,总是比查询的总记录数要少1000多条,几次看数据后发现有些数据并没有换行,而是写到上一行去了。在有了这个觉悟后,重新看了遍之前转别人的帖子,发现还是用fputcsv()函数比较靠谱,传入一个数组,作为一行的数据,由该函数自己去写换行和控列。感觉有些时候还是不要偷懒的好啊,虽然自己写","完成列分割,写"\n"完成空格,貌似是可行的,但是对于一些数据,并不一定能控制的好。
修改后的导出代码:
- header ( "Content-type:application/vnd.ms-excel" );
- header ( "Content-Disposition:filename=" . iconv ( "UTF-8", "GB18030", "query_user_info" ) . ".csv" );
- // 打开PHP文件句柄,php://output 表示直接输出到浏览器
- $fp = fopen('php://output', 'a');
- // 将中文标题转换编码,否则乱码
- foreach ($column_name as $i => $v) {
- $column_name[$i] = iconv('utf-8', 'GB18030', $v);
- }
- // 将标题名称通过fputcsv写到文件句柄
- fputcsv($fp, $column_name);
- $pre_count = 10000;
- for ($i=0;$i<intval($total_export_count/$pre_count)+1;$i++){
- $export_data = $db->getAll($sql." limit ".strval($i*$pre_count).",{$pre_count}");
- foreach ( $export_data as $item ) {
- $rows = array();
- foreach ( $item as $export_obj){
- $rows[] = iconv('utf-8', 'GB18030', $export_obj);
- }
- fputcsv($fp, $rows);
- }
- // 将已经写到csv中的数据存储变量销毁,释放内存占用
- unset($export_data);
- ob_flush();
- flush();
- }
- exit ();
php 用csv文件导出大量数据初方案的更多相关文章
- [转载] php用csv文件导出大量数据
header ( "Content-type:application/vnd.ms-excel" ); header ( "Content-Disposition:fil ...
- python使用pymongo访问MongoDB的基本操作,以及CSV文件导出
1. 环境. Python:3.6.1 Python IDE:pycharm 系统:win7 2. 简单示例 import pymongo # mongodb服务的地址和端口号mongo_url = ...
- 将CSV文件中的数据导入到SQL Server 数据库中
导入数据时,需要注意 CSV 文件中的数据是否包含逗号以及双引号,存在时,导入会失败 选择数据库 -> 右键 -> 任务 -> 导入数据 ,然后根据弹出的导入导出向导(如下图)中的提 ...
- csv文件批量导入数据到sqlite。
csv文件批量导入数据到sqlite. 代码: f = web.input(bs_switch = {}) # bs_switch 为from表单file字段的namedata =[i.split( ...
- MySQL添加CSV文件中的数据
一.MySQL添加csv数据 此问题是前几天整理数据的时候碰到的,数据存在 CSV文件中(200多万记录),通过python 往数据库中导入太慢了,后来使用MySQL 中自带的命令 LOAD DATA ...
- 基于CentOS的MySQL学习补充四--使用Shell批量从CSV文件里插入数据到数据表
本文出处:http://blog.csdn.net/u012377333/article/details/47022699 从上面的几篇文章中,能够知道怎样使用Shell创建数据库.使用Shell创建 ...
- 【SQL Server数据迁移】把csv文件中的数据导入SQL Server的方法
[sql] view plaincopy --1.修改系统参数 --修改高级参数 sp_configure 'show advanced options',1 go --允许即席分布式查询 sp_co ...
- CSV文件导出2
public void exportCSVFile( HttpServletResponse response, ResultSet rs,String fileName,String headers ...
- csv文件导出
参考博客:http://www.cnblogs.com/mingforyou/p/4103132.html 导入jar包javacsv.jar 链接:http://pan.baidu.com/s/1i ...
随机推荐
- JDBC的复习
什么是JDBC JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库.原来我们操作数据库是在控制台使用SQL语句来操作数据库,J ...
- VMware Workstation 12 Pro(安装CentOS7)
之前安装了一版 Ubuntu 14.04版本,发现蛮不好用的,果断放弃,换上CentOS7版本(在远程服务器上的安装方式除了网络设置有差异,基本相同) VMware Workstation 12 Pr ...
- CCNode作为容器实现显示区域剪裁
一直把ccnode当做ui元素的容器使用,比如一段带下划线的文字,我会在一个ccnode中加入一个label和一个sprite,然后作为一个整体传出. 在主界面聊天的时候遇到一个问题,一段聊天信息需要 ...
- jssip音视频及短信开发demo(中文注释完整版)
完整案例demo下载地址:http://download.csdn.net/download/qq_39421580/10214712 <!DOCTYPE html> <html l ...
- 一个简单的语义分析算法:单步算法——Python实现
以前 曾经有一个人教会我一件事 要学会相信一些看似不可能的事 当你真的相信的时候 或许 没有什么事情是不可能的 ——<秦时明月•与子同归> 在编译原理的众多书籍中,陈述了很多生成语法树 ...
- vagrant+docker搭建consul集群开发环境
HashiCorp 公司推出的Consul是一款分布式高可用服务治理与服务配置的工具.关于其配置与使用可以参考这篇文章 consul 简介与配置说明. 一般,我们会在多台主机上安装并启动 consul ...
- 太白老师 day06 编码 encode decode
ASCII : 字母, 数字, 特殊字符 字符:1个字节 数字: 1个字节 Unicode: 万国码, 包含所有文字 创建之初 字符: 2个字节 中文: 2个字节 升级: 字符: 4个字节 中文 : ...
- Shiro的校验Session是否过期处理的过程
首先开启定时扫描活跃的session进行校验 <!-- shiro会话管理 --> <!-- 即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中:会话可以是普通 Jav ...
- RocketMQ入门(简介、特点)
简介: RocketMQ作为一款纯java.分布式.队列模型的开源消息中间件,支持事务消息.顺序消息.批量消息.定时消息.消息回溯等. 发展历程: 1. Metaq(Metamorphosis) 1. ...
- 数据库,使用Druid 加密数据库密码
首先我们得下载一个druid-1.0.16.jar的包 其次键入命令 java -cp druid-1.0.16.jar com.alibaba.druid.filter.config.ConfigT ...