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+Html+缓存
Dec 20 PHP
比较时间段一与时间段二是否有交集的php函数
May 31 PHP
6种php上传图片重命名的方法实例
Nov 04 PHP
php去除字符串换行符示例分享
Feb 13 PHP
推荐一款MAC OS X 下php集成开发环境mamp
Nov 08 PHP
codeigniter发送邮件并打印调试信息的方法
Mar 21 PHP
PHP生成器简单实例
May 13 PHP
浅谈PHP中JSON数据操作
Jul 01 PHP
WordPress迁移时一些常见问题的解决方法整理
Nov 24 PHP
PHP实现根据时间戳获取周几的方法
Feb 26 PHP
PHP使用微信开发模式实现搜索已发送图文及匹配关键字回复的方法
Sep 13 PHP
PHP终止脚本运行三种实现方法详解
Sep 01 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 fopen 读取带中文URL地址的一点见解
2012/09/25 PHP
php实现设计模式中的单例模式详解
2014/10/11 PHP
Codeigniter购物车类不能添加中文的解决方法
2014/11/29 PHP
php返回字符串中所有单词的方法
2015/03/09 PHP
PHPCMS忘记后台密码的解决办法
2016/10/30 PHP
浅谈PHP中类和对象的相关函数
2017/04/26 PHP
关于laravel 子查询 &amp; join的使用
2019/10/16 PHP
Raphael一个用于在网页中绘制矢量图形的Javascript库
2013/01/08 Javascript
js数组与字符串的相互转换方法
2014/07/09 Javascript
jQuery中parent()方法用法实例
2015/01/07 Javascript
15款jQuery分布引导插件分享
2015/02/04 Javascript
浅析Bootstrap缩略图组件与警示框组件
2016/04/29 Javascript
浅析script标签中的defer与async属性
2016/11/30 Javascript
Ajax 加载数据 练习代码
2017/01/05 Javascript
js css3实现图片拖拽效果
2017/03/04 Javascript
很棒的vue弹窗组件
2017/05/24 Javascript
laravel5.4+vue+element简单搭建的示例代码
2017/08/29 Javascript
利用ES6实现单例模式及其应用详解
2017/12/09 Javascript
vue 属性拦截实现双向绑定的实例代码
2018/10/24 Javascript
Python中处理字符串之endswith()方法的使用简介
2015/05/18 Python
一个基于flask的web应用诞生 使用模板引擎和表单插件(2)
2017/04/11 Python
浅谈python装饰器探究与参数的领取
2017/12/01 Python
TensorFlow实现iris数据集线性回归
2018/09/07 Python
django项目搭建与Session使用详解
2018/10/10 Python
Python 2/3下处理cjk编码的zip文件的方法
2019/04/26 Python
python中查看.db文件中表格的名字及表格中的字段操作
2020/07/07 Python
eBay澳大利亚站:eBay.com.au
2018/02/02 全球购物
Uber Eats台湾:寻找附近提供送餐服务的餐厅
2018/05/07 全球购物
出纳员岗位职责风险
2014/03/06 职场文书
大学第二课堂活动总结
2014/07/08 职场文书
2014年乡镇妇联工作总结
2014/12/02 职场文书
胡雪岩故居导游词
2015/02/06 职场文书
消防安全月活动总结
2015/05/08 职场文书
《全神贯注》教学反思
2016/02/22 职场文书
《烈火英雄》观后感:致敬和平时代的英雄
2019/11/11 职场文书
Win11如何默认打开软件界面最大化?Win11默认打开软件界面最大化的方法
2022/07/15 数码科技