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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 一、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文件


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
数据采集 PHP
PHP中实现简单爬虫与数据解析
【8月更文挑战第31天】在互联网的海洋里,爬虫技术如同一艘探索船,帮助我们搜集和理解信息。本文将带你通过PHP语言,轻松实现一个简单的网页内容抓取工具,并展示如何从抓取的数据中解析出有用信息。我们将一起航行在代码的波浪中,体验从无到有构建一个基本爬虫的过程。
|
2月前
|
数据采集 JavaScript 数据挖掘
如何使用 PHP Simple HTML DOM Parser 轻松获取网页中的特定数据
本文介绍了使用PHP Simple HTML DOM Parser进行网页数据抓取的方法,尤其适用于从懂车帝二手车网站提取汽车品牌、价格和里程等关键信息。首先,安装并配置所需库,使用代理IP和设置cookie与useragent来模拟用户行为,避免被封。然后,通过编写PHP脚本,利用cURL获取网页内容,解析HTML并提取所需数据,最终将数据保存至CSV文件。文章强调了正确配置代理和用户代理的重要性,并提供了完整的PHP代码示例,以帮助读者理解和应用网页抓取技术。
如何使用 PHP Simple HTML DOM Parser 轻松获取网页中的特定数据
|
3月前
|
算法 大数据 数据处理
深入理解PHP中的生成器(Generators)
【7月更文挑战第28天】在PHP的世界中,生成器是一个强大而常被忽视的特性。它们允许开发者实现简单而高效的迭代器,优化内存使用并简化复杂运算。本文将深入探讨生成器的内部机制,展示如何利用这一特性来编写更加优雅和高效的代码。准备好,我们将一起揭开生成器的神秘面纱。
48 2
|
3月前
|
大数据 PHP 数据库
深入理解PHP中的生成器(Generators)
【7月更文挑战第17天】在PHP开发中,生成器是一个强大但常被忽视的特性,它允许开发者以迭代器的方式处理大量数据而不需要一次性将所有数据加载到内存。本文将介绍生成器的基本概念、使用场景和实现方法,帮助读者掌握如何利用生成器优化程序性能和提高代码的可读性与维护性。
|
4月前
|
存储 算法 大数据
深入理解PHP中的生成器(Generators)
【6月更文挑战第28天】在编程世界中,生成器是一个强大而常被忽视的特性。它们允许你在函数中定义一个迭代算法,却不需要一次性返回所有结果。本文将深入探讨PHP的生成器,解释其工作原理,展示如何创建和使用它们,以及讨论它们如何优化内存使用和提高性能。
33 2
|
4月前
|
存储 算法 大数据
深入理解PHP中的生成器(Generators)
【6月更文挑战第29天】在PHP的世界里,生成器是一个强大的工具,它允许你以迭代的方式处理大量数据,而不需要一次性将所有数据加载到内存中。本篇文章将深入探讨生成器的概念、用法和实际应用场景,帮助你掌握这一高效处理数据的利器。
|
4月前
|
存储 算法 PHP
深入理解PHP中的生成器(Generators)
【6月更文挑战第22天】在PHP的世界里,生成器是一个强大的功能,它允许你定义一个迭代器,而不需要实现迭代器接口。通过一个简单的关键字 "yield",你可以生成一个序列的值,每次只产生一个值,而不是一次性计算并存储所有的值。本文将带你深入了解生成器的工作原理,以及如何有效地使用它们来优化内存使用和提高代码效率。
|
3月前
|
前端开发 PHP 数据格式
【附带效果视频】php接口给前端返回流式数据,php使用event-stream进行数据推送,循环一次输出一次
【附带效果视频】php接口给前端返回流式数据,php使用event-stream进行数据推送,循环一次输出一次
133 0
|
4月前
|
存储 PHP
php处理带emoji表情的字符数据
php处理带emoji表情的字符数据
26 0
|
4月前
|
PHP
php+ajax传file文件数据
php+ajax传file文件数据
42 0