php使用fputcsv实现大数据的导出操作详解


Posted in PHP onFebruary 27, 2020

本文实例讲述了php使用fputcsv实现大数据的导出操作。分享给大家供大家参考,具体如下:

为了实验大数据的导出,我们这里先自已创建一张大表,表结构如下:

CREATE TABLE `tb_users` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID',
 `name` varchar(32) DEFAULT '' COMMENT '用户名',
 `age` tinyint(3) DEFAULT '0' COMMENT '用户年龄',
 `desc` varchar(255) DEFAULT '' COMMENT '用户描述',
 `phone` varchar(11) DEFAULT '' COMMENT '用户手机',
 `qq` varchar(16) DEFAULT '' COMMENT '用户QQ',
 `email` varchar(64) DEFAULT '' COMMENT '用户邮箱',
 `addr` varchar(255) DEFAULT '' COMMENT '用户地址',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 然后写个php脚本往这个表插入数据,代码如下:

<?php
set_time_limit(0);
ini_set('memory_limit', '128M');

//使用TP3.2的String类,php7下会报错,注意把类名换一下
require './String.class.php';
use Org\Util\NewString;

$begin = microtime(true);

$db = new mysqli('127.0.0.1', 'root', '', 'test');

if($db->connect_error) {
  die('connect error');
}
//数据插入语句
$insSql = '';

//一百万数据,分200步,每步插入5000条
$step = 200;
$nums = 5000;

for($s = 0; $s < $step; ++$s) {
  $insSql = 'INSERT INTO tb_users VALUES';
  for($n = 0; $n < $nums; ++$n) {
    $name = NewString::randString(3, 4);
    $age = mt_rand(1, 120);
    $desc = NewString::randString(64, 4);
    $phone = NewString::randString(11, 1);
    $qq = NewString::randString(13, 1);
    $email = $qq . '@qq.com';
    $addr = NewString::randString(128, 4);
    $insSql .= "(NULL, '{$name}', $age, '{$desc}', '{$phone}', '{$qq}', '{$email}', '{$addr}'),";
  }
  $insSql = rtrim($insSql, ',');
  $db->query($insSql);
}
$end = microtime(true);
echo '用时:', $end - $begin;

$db->close();

里面用到的TP3.2的String类大家自行上TP官网下载。整个用时2个多小时,最后数据大小662M。

现在我们用php提供的fputcsv来导出这一百万的数据,原理就是打开一个标准输出流,然后把数据按一万条来分割,每一万条就刷新缓冲区。

<?php
set_time_limit(0);
ini_set('memory_limit', '128M');

$fileName = date('YmdHis', time());
header('Content-Type: application/vnd.ms-execl');
header('Content-Disposition: attachment;filename="' . $fileName . '.csv"');

$begin = microtime(true);

//打开php标准输出流
//以写入追加的方式打开
$fp = fopen('php://output', 'a');

$db = new mysqli('127.0.0.1', 'root', '', 'test');

if($db->connect_error) {
  die('connect error');
}

//我们试着用fputcsv从数据库中导出1百万的数据
//我们每次取1万条数据,分100步来执行
//如果线上环境无法支持一次性读取1万条数据,可把$nums调小,$step相应增大。
$step = 100;
$nums = 10000;

//设置标题
$title = array('ID', '用户名', '用户年龄', '用户描述', '用户手机', '用户QQ', '用户邮箱', '用户地址');
foreach($title as $key => $item) {
  $title[$key] = iconv('UTF-8', 'GBK', $item);
}
//将标题写到标准输出中
fputcsv($fp, $title);

for($s = 1; $s <= $step; ++$s) {
  $start = ($s - 1) * $nums;
  $result = $db->query("SELECT * FROM tb_users ORDER BY id LIMIT {$start},{$nums}");
  
  if($result) {
    while($row = $result->fetch_assoc()) {
      foreach($row as $key => $item) {
        //这里必须转码,不然会乱码
        $row[$key] = iconv('UTF-8', 'GBK', $item);
      }
      fputcsv($fp, $row);
    }
    $result->free();
    
    //每1万条数据就刷新缓冲区
    ob_flush();
    flush();
  }
}

$end = microtime(true);
echo '用时:', $end - $begin;

整个过程用时5分钟,最终生成的csv文件大小420M。

php使用fputcsv实现大数据的导出操作详解

php使用fputcsv实现大数据的导出操作详解

php使用fputcsv实现大数据的导出操作详解

对于如何用phpexcel导出大数据,并没有什么比较好的方案,phpexcel提供的一些缓存方法,数据压缩,虽然内存使用小了,但所用时间则加长了,时间换空间,显然并不是最好的方案。比较靠谱的方法还是生成多个下载链接地址,把你要下载的数据,以get形式传递当前页数,后台进行数据分页然后导出。

<a href="/downSearchData.php?参数1=值1&参数2=值2&page=1" rel="external nofollow" >下载汇总结果1</a>
<a href="/downSearchData.php?参数1=值1&参数2=值2&page=2" rel="external nofollow" >下载汇总结果2</a>
<a href="/downSearchData.php?参数1=值1&参数2=值2&page=3" rel="external nofollow" >下载汇总结果3</a>

 比如你有一个查询数据表单,ID为searchFrm,然后你想把导出数据按1万条分割(phpexcel一次导出1万条是没有问题的,效率还行)

<form id="searchFrm">
  姓名<input type="text" name="uname">
  <input type="button" id="searchDataBtn" value="导出汇总结果">
</form>
<div id="searchDataList"></div>

<script type="script">
  $("#searchDataBtn").on("click", function() {
    var params = $("#searchFrm").serialize();
    
    //获取查询数据的条数
    $.get("/getSearchDataRows?" + params, function(data) {
      var downDataList = "";
      if(data["rows"]) {
        //rows是数据总条数,pageSize是一页多少条
        var pageNum = Math.ceil(data["rows"] / data["pageSize"]);
        for(var i = 1; i <= pageNum; ++i) {
          downDataList += "<a href='/downSearchData.php?'" + params + "&page=" + i + ">下载汇总结果" + i + "</a>  ";
        }
        $("#searchDataList").html(downDataList);
      } else {
        $("#searchDataList").text("没有数据");
      }
    }, "json");
    return false;
  });
</script>

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
利用 window_onload 实现select默认选择
Oct 09 PHP
Smarty模板快速入门
Jan 04 PHP
fleaphp常用方法分页之Pager使用方法
Apr 23 PHP
PHP在线生成二维码(google api)的实现代码详解
Jun 04 PHP
PHP开发框架kohana3 自定义路由设置示例
Jul 14 PHP
ThinkPHP中的三大自动简介
Aug 22 PHP
PHP 使用redis简单示例分享
Mar 05 PHP
php操作redis缓存方法分享
Jun 03 PHP
8个必备的PHP功能开发
Oct 02 PHP
PHP获取昨天、今天及明天日期的方法
Feb 03 PHP
详解Yaf框架PHPUnit集成测试方法
Dec 27 PHP
PHP实现图片防盗链破解操作示例【解决图片防盗链问题/反向代理】
May 29 PHP
gearman中任务的优先级和返回状态实例分析
Feb 27 #PHP
gearman中worker常驻后台,导致MySQL server has gone away的解决方法
Feb 27 #PHP
PHP使用gearman进行异步的邮件或短信发送操作详解
Feb 27 #PHP
gearman管理工具GearmanManager的安装与php使用方法示例
Feb 27 #PHP
php使用gearman进行任务分发操作实例详解
Feb 26 #PHP
php实现根据身份证获取精准年龄
Feb 26 #PHP
ThinkPHP5与单元测试PHPUnit使用详解
Feb 23 #PHP
You might like
discuz authcode 经典php加密解密函数解析
2020/07/12 PHP
php源码加密 仿微盾PHP加密专家(PHPCodeLock)
2010/05/06 PHP
gearman管理工具GearmanManager的安装与php使用方法示例
2020/02/27 PHP
JavaScript中使用正则匹配多条,且获取每条中的分组数据
2010/11/30 Javascript
超轻量级的基于jquery的三级展开列表
2011/04/26 Javascript
jquery blockUI 遮罩不能消失与不能提交的解决方法
2011/09/17 Javascript
DOM和XMLHttpRequest对象的属性和方法整理
2012/01/04 Javascript
javascript学习笔记(四) Number 数字类型
2012/06/19 Javascript
如何判断鼠标是否在DIV的区域内
2013/11/13 Javascript
如何在node的express中使用socket.io
2014/12/15 Javascript
JavaScript在控件上添加倒计时功能的实现代码
2017/07/04 Javascript
在 React、Vue项目中使用SVG的方法
2018/02/09 Javascript
解决Webpack 热部署检测不到文件变化的问题
2018/02/22 Javascript
koa2 用户注册、登录校验与加盐加密的实现方法
2019/07/22 Javascript
vuex存储token示例
2019/11/11 Javascript
jquery实现两个div中的元素相互拖动的方法分析
2020/04/05 jQuery
基于postman获取动态数据过程详解
2020/09/08 Javascript
jQuery是用来干什么的 jquery其实就是一个js框架
2021/02/04 jQuery
[52:02]完美世界DOTA2联赛PWL S2 FTD.C vs SZ 第一场 11.27
2020/11/30 DOTA
linux系统使用python获取cpu信息脚本分享
2014/01/15 Python
Python单链表的简单实现方法
2014/09/23 Python
利用 python 对目录下的文件进行过滤删除
2017/12/27 Python
python2.7 json 转换日期的处理的示例
2018/03/07 Python
Django migrations 默认目录修改的方法教程
2018/09/28 Python
用Python实现筛选文件脚本的方法
2018/10/27 Python
详解Python3定时器任务代码
2019/09/23 Python
手把手教你进行Python虚拟环境配置教程
2020/02/03 Python
python实现暗通道去雾算法的示例
2020/09/27 Python
Python 转移文件至云对象存储的方法
2021/02/07 Python
儿科护士自我鉴定
2013/10/14 职场文书
个人求职简历的自我评价
2013/10/19 职场文书
销售人员自我评价
2014/02/01 职场文书
会计学生自我鉴定
2014/02/06 职场文书
乡镇八一建军节活动方案
2014/08/24 职场文书
出国导师推荐信
2015/03/25 职场文书
mysql中数据库覆盖导入的几种方式总结
2022/03/25 MySQL