百万级大数据量导出方案思路

注意的问题点:


1、Excel

Excel2003版最大行数是65535行,Excel2007版的行数(1048576行)才能达到我们的要求,所以我们需要使用Excel的版本必须为2007版及以上,所以想几百万条轻轻松松一次性导入一张EXCEL表是不行的,你起码需要进行数据分割,保证数据不能超过104W一张表,PHPexcel内存溢出:既然数据限制在104W,那么就数据分割,于是你尝试50W一次导入表,然而PHPexcel内部有函数报内存溢出错误,然后你就不断的调小数据量,直到5W一次导入你都会发现有内存溢出错误。这是为什么呢,虽然你分割数据来导入多个数据表,但是最后PHPexcel内部还是一次性把所有表数据放进一个变量中来创建文件……额,这几百万数据一个变量存储,你想内存不溢出,还真有点困难。 
(PHPExcel也有解决方案,PHPExcel_Settings::setCacheStorageMethod方法更改缓冲方式来减小内存的使用)


2、超时问题


     脚本允许运行的时间,一般默认为30秒,如果超过了此设置,脚本返回一个致命的错误。
     方法一
           在php.ini可以通过定义max_execution_time来设置PHP页面的最大执行时间。
     方法二
            在脚本中添加set_time_limit(0);
            这个函数指定了当前所在php脚本的最大执行时间,假设为800秒,实际上 最大执行时间=php.ini里的max_execution_time数值 - 当前脚本已经执行的时间 + 设定值
    假如php.ini里的max_execution_time=30,当前脚本已经执行5秒,则:
        最大执行时间=30-5+800=825秒。
             括号里边的数字是执行时间,如果为零说明永久执行直到程序结束,如果为大于零的数字,则不管程序是否执行完成,到了设定的秒数,程序结束。
             注意:这个函数的运行需要你关闭安全模式,在php.ini中将safe_mode = Off 安全模式设置为Off,否则将会出现错误


3、内存溢出问题


       php默认内存限制是128M,如果一次性的把所有数据从数据库取出填充到内存中,一下不光内存存储不够,并且如果服务器CPU配置不高的话使用率一下也能达到100%,会造成服务器卡负载。可以从两个方向解决:
      一 配置方向,解决方法:
                方法一  直接在程序中添加代码:
                       ini_set('memory_limit', '1024M')。
                方法二  修改php.ini配置文件
                       查找到memory_limit = 128M这一行,将128M改大点。
                       重启服务器。
                方法三  修改 .htaccess
                       php_value memory_limit XXX M ;

                注意: php内存溢出时,memory_limit设置太大会影响系统速度,因为系统和数据库及其他程序同样需要内存空间,一般系统和数据库内存空间是自己分配的
      二  代码中用yield生成器(从PHP 5.5开始引入的)来处理内存溢出。具体可以参考一篇大神的文章PHP百万级数据导出方案(生成器直接输出单个CSV)


4、缓存(buffer)过多


       PHP也有自己的buffer机制。默认是开启的,大小默认4096(4kb),在php.ini配置文件中由output_buffering配置。当执行php执行echo,print的时候,是先将数据写入php的buffer,当一个php buffer写满的时候,脚本进程会将php 的buffer数据发送给系统内核交由tcp传给浏览器显示,数据流程:
    echo/pring -> php buffer -> tcp buffer (服务器系统buffer)-> 浏览器 buffer ->浏览器展示

     当你用PHP原生函数putcsv()其实就使用到了输出缓存buffer,如果你把几百万的数据一直用这个函数输出,会导致输出缓存太大而报错的,因此我们每隔一定量的时候,必须进行将输出缓存中的内容取出来,设置为等待输出状态。可以在代码中添加:
     

ob_flush();  //把数据从PHP的缓冲(buffer)中释放出来
flush();       //把不在缓冲(buffer)中的或者说是被释放出来的数据发送到浏览器


分析完上面的注意点,假设数据量是几百万,我们可以从以下几个方向进行优化:

  • 从数据库中进行数据量分批读取读取,以防变量内存溢出,
  • 尽量选择数据保存文件格式是csv文件,以方便导出之后的阅读、导入数据库等操作。
  • 以防不方便excel读取csv文件,我们需要104W之前就得把数据分割进行多个csv文件保存
  • 多个csv文件输出给用户下载是不友好的,我们还需要把多个csv文件进行压缩,最后提供给一个ZIP格式的压缩包给用户下载就好。


另外其他相关信息:
      

CSV的Excel支持GBK编码,一定要转换,否则乱码


使用linux命令 ps 或 top 命令查看进程时, 能看到内存消耗的百分比和大小
查看php运行目录命令:
which php
/usr/bin/php

ps aux | grep -c php-fpm      //查看php-fpm进程数
/usr/bin/php  -i|grep mem   //查看运行内存
/etc/init.d/php-fpm restart   //重启php-fpm

memory_get_usage 指当前脚本正在使用的内存, memory_get_peak_usage 返回分配给 PHP 内存的峰值, 举例说明:
1、 数据库读出来千万条数据,假如说需要消耗100MB,那么系统会分配给进程 100MB
2、当处理完数据后 unset 掉, 其实当前进程的消耗的内存并不会变小, 即不会释放100MB空间。unset后可以让 memory_get_peak_usage 不继续升高, 程序执行被分配的内存(进程里的内存)仍然要以 memory_get_peak_usage 为准
3、内存被分划为, "已使用" 和 "空闲", unset 只会把 "已使用" 变为 "空闲", 下次内存请求时会先去"空闲"里取, 程序结束, GC 才会释放全部内存


ob_start() : 激活php output_buffering机制,在不写参数情况下,ob_start()将php buffer空间设置
到了足够大 ,只有脚本执行结束,或者调用ob_end_flush函数,才会把数据发送给客户端浏览器。ob_start()函数内的参数可以设置output_buffering大小及输出机制。具体可以查看手册。
ob_end_flush与ob_end_clean:都会关闭ouput_buffering机制。不同的是,ob_end_flush只是把php buffer中的数据传送到浏览器,而ob_clean_clean将php bufeer中的数据清空,但不发送给客户端浏览器。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java8新特性及实战视频教程完整版Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda 表达式可以使代码变的更加简洁紧凑。Java8实战视频-01让方法参数具备行为能力Java8实战视频-02Lambda表达式初探Java8实战视频-03Lambda语法精讲Java8实战视频-04Lambda使用深入解析Java8实战视频-05Lambda方法推导详细解析-上.wmvJava8实战视频-06Lambda方法推导详细解析-下Java8实战视频-07Stream入门及Stream在JVM中的线程表现Java8实战视频-08Stream知识点总结Stream源码阅读Java8实战视频-09如何创建Stream上集Java8实战视频-10如何创建Stream下集.wmvJava8实战视频-11Stream之filter,distinct,skip,limit,map,flatmap详细介绍Java8实战视频-12Stream之Find,Match,Reduce详细介绍Java8实战视频-13NumericStream的详细介绍以及和Stream之间的相互转换Java8实战视频-14Stream综合练习,熟练掌握API的用法Java8实战视频-15在Optional出现之前经常遇到的空指针异常.wmvJava8实战视频-16Optional的介绍以及API的详解Java8实战视频-17Optional之flatMap,综合练习,Optional源码剖析Java8实战视频-18初识Collector体会Collector的强大Java8实战视频-19Collector使用方法深入详细介绍-01Java8实战视频-20Collector使用方法深入详细介绍-02Java8实战视频-21Collector使用方法深入详细介绍-03.wmvJava8实战视频-22Collector使用方法深入详细介绍-04Java8实战视频-23Collector原理讲解,JDK自带Collector源码深度剖析Java8实战视频-24自定义Collector,结合Stream的使用详细介绍Java8实战视频-25Parallel Stream编程体验,充分利用多核机器加快计算速度Java8实战视频-26Fork Join框架实例深入讲解Java8实战视频-27Spliterator接口源码剖析以及自定义Spliterator实现一个Stream.wmvJava8实战视频-28Default方法的介绍和简单的例子Java8实战视频-29Default方法解决多重继承冲突的三大原则详细介绍Java8实战视频-30多线程Future设计模式原理详细介绍,并且实现一个Future程序Java8实战视频-31JDK自带Future,Callable,ExecutorService介绍Java8实战视频-32实现一个异步基于事件回调的Future程序.wmvJava8实战视频-33CompletableFuture用法入门介绍Java8实战视频-34CompletableFuture之supplyAsync详细介绍Java8实战视频-35CompletableFuture流水线工作,join多个异步任务详细讲解Java8实战视频-36CompletableFuture常用API的重点详解-上Java8实战视频-37CompletableFuture常用API的重点详解-下Java8实战视频-38JDK老DateAPI存在的问题,新的DateAPI之LocalDate用法及其介绍.wmvJava8实战视频-39New Date API之LocalTime,LocalDateTime,Instant,Duration,Period详细介绍Java8实战视频-40New Date API之format和parse介绍

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值