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 中文处理函数集合
Aug 27 PHP
PHP base64+gzinflate压缩编码和解码代码
Oct 03 PHP
PHP中的float类型使用说明
Jul 27 PHP
PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)
May 07 PHP
PHP获取http请求的头信息实现步骤
Dec 16 PHP
php将url地址转化为完整的a标签链接代码(php为url地址添加a标签)
Jan 17 PHP
测试php连接mysql是否成功的代码分享
Jan 24 PHP
PHP5中实现多态的两种方法实例分享
Apr 21 PHP
浅谈使用 PHP 进行手机 APP 开发(API 接口开发)
Aug 11 PHP
PHP的压缩函数实现:gzencode、gzdeflate和gzcompress的区别
Jan 27 PHP
PHP模板引擎Smarty内建函数foreach,foreachelse用法分析
Apr 11 PHP
php文件后缀不强制为.php的实操方法
Sep 18 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
解析如何通过PHP函数获取当前运行的环境 来进行判断执行逻辑(小技巧)
2013/06/25 PHP
详解PHP实现异步调用的4种方法
2016/03/14 PHP
php使用高斯算法实现图片的模糊处理功能示例
2016/11/11 PHP
JavaScript 字符串乘法
2009/08/20 Javascript
利用JS进行图片的切换即特效展示图片
2013/12/03 Javascript
iframe如何动态创建及释放其所占内存
2014/09/03 Javascript
浅谈jQuery中height与width
2015/07/06 Javascript
js实现的万能flv网页播放器代码
2016/04/30 Javascript
react-native中ListView组件点击跳转的方法示例
2017/09/30 Javascript
Postman模拟发送带token的请求方法
2018/03/31 Javascript
vue debug 二种方法
2018/09/16 Javascript
浅析JavaScript异步代码优化
2019/03/18 Javascript
微信小程序实现搜索功能并跳转搜索结果页面
2019/05/18 Javascript
Vue源码分析之Vue实例初始化详解
2019/08/25 Javascript
java实现单链表增删改查的实例代码详解
2019/08/30 Javascript
使用JS来动态操作css的几种方法
2019/12/18 Javascript
解决React在安装antd之后出现的Can't resolve './locale'问题(推荐)
2020/05/03 Javascript
[04:47]DOTA2-潍坊风行电子俱乐部探秘
2014/08/08 DOTA
Python记录详细调用堆栈日志的方法
2015/05/05 Python
Python命令启动Web服务器实例详解
2017/02/23 Python
Python 中 list 的各项操作技巧
2017/04/13 Python
DataFrame中去除指定列为空的行方法
2018/04/08 Python
python用post访问restful服务接口的方法
2018/12/07 Python
python基于SMTP协议发送邮件
2019/05/31 Python
Python 类的私有属性和私有方法实例分析
2019/09/29 Python
Django 实现外键去除自动添加的后缀‘_id’
2019/11/15 Python
python json.dumps() json.dump()的区别详解
2020/07/14 Python
解决python的空格和tab混淆而报错的问题
2021/02/26 Python
JD Sports比利时官网:英国领先的运动鞋和运动服饰零售商
2018/10/10 全球购物
整个世界的设计师家具在哈恩:Designathome
2019/03/25 全球购物
文明美德伴我成长演讲稿
2014/05/12 职场文书
2014年作风建设工作总结
2014/10/29 职场文书
八年级地理课件资料及考点知识分享
2019/08/30 职场文书
python获取淘宝服务器时间的代码示例
2021/04/22 Python
Python爬虫基础之爬虫的分类知识总结
2021/05/13 Python
Golang 链表的学习和使用
2022/04/19 Golang