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 相关文章推荐
PHP header()函数使用详细(301、404等错误设置)
Apr 17 PHP
关于PHP session 存储方式的详细介绍
Jun 25 PHP
PHP编译安装中遇到的两个错误和解决方法
Aug 20 PHP
php定义参数数量可变的函数用法实例
Mar 16 PHP
php实现的一个简单json rpc框架实例
Mar 30 PHP
学习php设计模式 php实现门面模式(Facade)
Dec 07 PHP
PHP抓取及分析网页的方法详解
Apr 26 PHP
PHP+iframe图片上传实现即时刷新效果
Nov 18 PHP
yii框架无限极分类的实现方法
Apr 08 PHP
CI框架教程之优化验证码机制详解【验证码辅助函数】
Apr 16 PHP
PHP之多条件混合筛选功能的实现方法
Oct 09 PHP
JS中彻底删除JSON对象组成的数组中的元素
Sep 22 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
session 的生命周期是多长
2006/10/09 PHP
isset和empty的区别
2007/01/15 PHP
php 缓存函数代码
2008/08/27 PHP
PHP 获取远程文件大小的3种解决方法
2013/07/11 PHP
PHP+Mysql树型结构(无限分类)数据库设计的2种方式实例
2014/07/15 PHP
phpMyAdmin安装并配置允许空密码登录
2015/07/04 PHP
android上传图片到PHP的过程详解
2015/08/03 PHP
PHP在线书签系统分享
2016/01/04 PHP
php上传后台无法收到数据解决方法
2019/10/28 PHP
THINKPHP-Apache服务器中使用Alias虚拟目录URL重写 隐藏index.php
2021/03/09 PHP
js 对联广告、漂浮广告封装类(IE,FF,Opera,Safari,Chrome
2009/11/26 Javascript
火狐textarea输入法的bug的触发及解决
2013/07/24 Javascript
纯文字版返回顶端的js代码
2013/08/01 Javascript
Jquery绑定事件(bind和live的区别介绍)
2013/08/23 Javascript
javascript的事件触发器介绍的实现
2014/06/05 Javascript
jquery插件bootstrapValidator数据验证详解
2016/11/09 Javascript
ES6概念 Symbol.keyFor()方法
2016/12/25 Javascript
vue中如何引入jQuery和Bootstrap
2017/04/10 jQuery
Nodejs连接mysql并实现增、删、改、查操作的方法详解
2018/01/04 NodeJs
微信小程序如何获取用户手机号
2018/01/26 Javascript
如何编写一个d.ts文件的步骤详解
2018/04/13 Javascript
解决ie11 SCRIPT5011:不能执行已释放Script的代码问题
2019/05/05 Javascript
少女风vue组件库的制作全过程
2019/05/15 Javascript
js实现跟随鼠标移动的小球
2019/08/26 Javascript
vue项目中使用rem,在入口文件添加内容操作
2020/11/11 Javascript
wxPython定时器wx.Timer简单应用实例
2015/06/03 Python
Python实现线程池代码分享
2015/06/21 Python
pycharm new project变成灰色的解决方法
2019/06/27 Python
Python 一行代码能实现丧心病狂的功能
2020/01/18 Python
使用 Python 在京东上抢口罩的思路详解
2020/02/27 Python
小学生关于梦想的演讲稿
2014/08/22 职场文书
中秋节随笔
2015/08/15 职场文书
2016八一建军节慰问信
2015/11/30 职场文书
mysql 8.0.24 安装配置方法图文教程
2021/05/12 MySQL
十大必看国产动漫排名,魁拔上线,第二曾在日本播出
2022/03/18 国漫
Python正则表达式中flags参数的实例详解
2022/04/01 Python