PHP迭代生成器秒级导出500万数据

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 一、PHP迭代生成器1.PHP性能优化利器:迭代生成器 yield理解很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显。但是,生成器功能的确非常有用。

一、PHP迭代生成器


1.PHP性能优化利器:迭代生成器 yield理解


很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显。但是,生成器功能的确非常有用。


2.迭代生成器的优点


直接讲概念估计你听完还是一头雾水,所以我们先来说说优点,也许能勾起你的兴趣。那么迭代生成器有哪些优点,如下:

  • 生成器会对PHP应用的性能有非常大的影响
  • PHP代码运行时节省大量的内存
  • 比较适合计算大量的数据


二、快速生成百万条测试数据


这里推荐数据库的蠕虫复制命令

先建好表后,插2条测试数据后,执行几次下列命令,即可指数增长

INSERT INTO user (username,phone,city) SELECT username,phone,city FROM user;


三、实战一(100w数据导出1个csv文件,在浏览器下载)


1.解决数据查询内存溢出


了解完生成器yield原理之后,我们还需要解决一个问题,我们常用的mysql查询函数是mysqli_query(connection,query,resultmode);,通常都是直接填写第一第二个参数就直接查询,但该函数默认的是对全部结果集进行缓存,这会导致数据过多的时候,内存也会溢出。因此,我们需要设置第三个参数为MYSQLI_USE_RESULT来逐行读取结果集。那或许您有疑问为什么不直接 遍历该mysqli_query()方法返回的结果来当每一行数据写到CSV中,而还要用yield来存储一次每行数据再写到CSV中呢?其实这是因为mysqli_query()返回的结果是mysqli_result Object形式,而fputcsv()这个方法要求第二个参数为数组。所以yield的作用就是中转站,但是他是一行行运输数据,而不是读多行来运输数据。


<?php
/*
 * 该方法是把数据库读出的数据进行CSV文件输出,能接受百万级别的数据输出,因为用生成器,不用担心内存溢出。
 * @param string $sql 需要导出的数据SQL
 * @param string $mark 生成文件的名字前缀
 *
 */
function exportCsv($sql,$fileName)
{
    //让程序一直运行
    set_time_limit(0);
//设置程序运行内存
    ini_set('memory_limit', '128M');
    header('Content-Encoding: UTF-8');
    header("Content-type:application/vnd.ms-excel;charset=UTF-8");
    header('Content-Disposition: attachment;filename="' . $fileName . '.csv"');
    //打开php标准输出流
    $fp = fopen('php://output', 'a');
    //添加BOM头,以UTF8编码导出CSV文件,如果文件头未添加BOM头,打开会出现乱码。
    fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));
    //添加导出标题
    fputcsv($fp, ['id', 'username', 'phone','city']);
    foreach (getExportData($sql) as $item) {
        //向csv表格中添加每一行数据
        fputcsv($fp, $item);
    }
    fclose($fp);  //每生成一个文件关闭
}
/**
 * 获取要导出的数据
 * 使用迭代生成器来缓存mysql查询结果,返回类型为数组
 * @param $sql
 * @return Generator
 */
function getExportData($sql){
    //连接数据库
    $con = mysqli_connect("localhost", "root", "");
    //连接数据库报错信息
    if (!$con) {
        die('Could not connect: ' . mysqli_error());
    }
    mysqli_select_db($con, "demo");
    mysqli_query($con,'set names utf8');
    //该处用MYSQLI_USE_RESULT 就是不缓存结果集中,也是为了避免内存溢出,相当于mysql_unbuffered_query
    foreach (mysqli_query($con, $sql,MYSQLI_USE_RESULT) as $row ){  //
        yield $row;
    }
    $con->close();
}
//要导出的数据
$sql = 'SELECT id,username,phone,city FROM `user`  where id < 1000000';
$mark = 'export';
exportCsv($sql,$mark);
?>
复制代码


四、实战二(100w数据导出多个csv文件,在文件夹中保存)


<?php
/*
 * 该方法是把数据库读出的数据进行CSV文件输出,能接受百万级别的数据输出,因为用生成器,不用担心内存溢出。
 * @param string $sql 需要导出的数据SQL
 * @param string $mark 生成文件的名字前缀
 *
 */
function putCsv($sql, $mark)
{
    set_time_limit(0);
    $file_num = 0;  //文件名计数器
    $fileNameArr = array();
    $fp = fopen($mark .'_'.$file_num .'.csv', 'w'); //生成临时文件
    $fileNameArr[] = $mark .'_'.$file_num .'.csv';
    fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));//转码,防止乱码
    //添加导出标题
    fputcsv($fp, ['id', 'type_id', 'state','addtime','usetime']);
    foreach (query($sql) as $a) {
        fputcsv($fp, $a);
    }
    fclose($fp);  //每生成一个文件关闭
}
//生成器来缓存mysql查询结果,返回类型为数组
function query($sql){
    //连接数据库
    $con = mysqli_connect("localhost", "root", "");
    //连接数据库报错信息
    if (!$con) {
        die('Could not connect: ' . mysqli_error());
    }
    mysqli_select_db($con, "demo");
    mysqli_query($con,'set names utf8');
    //该处用MYSQLI_USE_RESULT 就是不缓存结果集中,也是为了避免内存溢出,相当于mysql_unbuffered_query
    foreach (mysqli_query($con, $sql,MYSQLI_USE_RESULT) as $row ){  //
        yield $row;
    }
    $con->close();
}
//数据库总数据
$count = 1000000;
//文件名称
$mark = 'test';
//一个excel保存的条数
$limit = 500000;
$page = 1;
$i = 0;
do
{
    $i+= $limit;
    //计算偏移量
    $start = ($page-1)*$limit;
    $sql = "SELECT id,type_id,state,addtime,usetime FROM `shop_ercode_records` limit {$start}".','."{$limit}";
    putCsv($sql,$mark.$i);
    $page++;
} while ($i<$count);
?>
复制代码


五、总结


  1. 浏览器只能同时下载一个文件,循环导出,浏览器最后智能下载最后一个文件
  2. 导出的数据到csv能打开查看的只到100w行,如果超过100w行,进行导出多个csv文件


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
JSON PHP 数据格式
php案例:$_ENV的数据怎么样才能显示出来.$_ENV的简单运用
php案例:$_ENV的数据怎么样才能显示出来.$_ENV的简单运用
php案例:$_ENV的数据怎么样才能显示出来.$_ENV的简单运用
php案例:用代码的方式创建目录+文件+写入数据(都由你定)
php案例:用代码的方式创建目录+文件+写入数据(都由你定)
php案例:用代码的方式创建目录+文件+写入数据(都由你定)
|
3月前
|
JSON PHP 数据格式
php 删掉空的数组 json数据. 空数据(false 0 ““ null)
php 删掉空的数组 json数据. 空数据(false 0 ““ null)
php 删掉空的数组 json数据. 空数据(false 0 ““ null)
|
3月前
|
JSON PHP 数据格式
php对‘[{“id“:“1“,“name“:“cyg”},{“id“:“2“,“name“:“liwen“}]json数据进行修改删除操作
php对‘[{“id“:“1“,“name“:“cyg”},{“id“:“2“,“name“:“liwen“}]json数据进行修改删除操作
php对‘[{“id“:“1“,“name“:“cyg”},{“id“:“2“,“name“:“liwen“}]json数据进行修改删除操作