您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > php

PHP导出百万条数据方法

时间:2019-09-11 10:43:30  来源:  作者:

公司目前有一个需求,需要对一个日增量在20万+数据量的数据表中的数据进行可自定义条件筛选的导出数据,该功能需要对多个部门进行开发使用,要保证功能可用的前提下,尽量优化体验。

首先介绍一下当前可利用的资源:

1、MySQL - 一主库双从库。

2、分布式服务器集群,选择其中一台中型机作为脚本执行载体。

3、文件系统 - 可以支持上传大数据量文件。

4、编程语言php

技术难点:

1、数据太大,对服务器配置要求较高,导出过程中涉及数据的处理(例如各种ID转换名称等操作,我们这次需求这种太多了~~非常的坑)对内存消耗很大,其次涉及到文件压缩,因此对CPU要求较高。

2、因为是跨系统部署,如果走接口,数据量随随便便上百M,传输速度太慢(项目是对外网开放的,然后数据只允许内网访问),那么该如何解决?

3、数据安全性较高,需要对所有导出进行记录,那么如何保证数据安全?

| 技术方案

第一步:设计数据库,对所有导出任务进行实时记录,也可以采用redis,为了方便数据的持久化,我最终采用了mysql数据库的方案。表结构具体包括:ID、用户ID、用户名、发起请求时间、导出具体的参数(包括各个维度的参数选择等,具体根据自身业务而定),任务是否正在处理标识(防止任务多次被处理),导出是否成功标识(可以与前一个用一个字段区分),删除标识等(假删除,便于记录用户实际操作日志)。

第二步:前台界面编写,具体包括参数选择、导出记录列表等,作用:触发导出任务创建,记录于导出表中,状态:待处理。

第三步:编写导出脚本对任务进行监控并处理,如果有导出任务自动对其执行导出操作。

这里有一个小问题:为什么不在前台触发任务的时候直接执行导出,而是有单独的脚本来执行导出呢?这就是现实业务导致的,因为我们对外开放的机器中有一些是配置很低的,为了保证导出的成功率,我们需要一台配置较高的机器来独立执行导出任务。

| 导出流程

具体流程参考下图

PHP导出百万条数据方法

 

| 代码实现

这里主要着重介绍一下导出脚本的代码,其他步骤的代码根据自己的业务自行编写就可以了。

注意:因为数据量过大~一次性导出可想而知是不合理的,所以我使用了分页导出的形式~

首先查询数据总条数、然后通过每页导出的条数来计算具体导出的页数~

# 获取数据总条数
$dataCount = Data_ExportModel::getExportZipTotalCount($params);
$dataCount = $dataCount[0]['count_num'];
# csv
# 输出Excel文件头,可把user.csv换成你要的文件名
$mark = '/tmp/export';
$stepLen = 20000;//每次只从数据库取100000条以防变量缓存太大
# 每隔$limit行,刷新一下输出buffer,不要太大,也不要太小
$limit = 20000;
$maxFileCount = 1000000;
# buffer计数器
$cnt = 0;
$head = self::initColumnDataV2(); // 表头部分根据自身业务自行调整
$fileNameArr = array();
$salesStatisticsData = array();
$startLimitId = 0;

首次导出的每页条数我定的10万条,后来发现对内存消耗过大,改成了两万条,这样的导出速度会慢一点,建议五万条比较适中一点。

for ($j = 0; $j < ceil($dataCount / $maxFileCount); $j++) {
 $startSelect = ceil($maxFileCount / $stepLen)*$j;
 $fileCsvName = $mark . '_'.$j*$maxFileCount.'_' . ($j+1)*$maxFileCount . '.csv';
 $fp = fopen($fileCsvName, 'w'); //生成临时文件
 $fileNameArr[] = $fileCsvName;
 # 将数据通过fputcsv写到文件句柄
 fputcsv($fp, $head);
 for ($i = 0; $i < 50; $i++) { // 单个文件支持100万数据条数
 $startNum = $j*$maxFileCount + $i*$limit;
 if ($startNum > $dataCount) {
 break; // 跳出循环
 }
 # 查询数据
 $dataSource = Data_ExportModel::getExportZipTotalInfo($params, $startNum, $stepLen, $startLimitId);
 $endMicroTime = microtime(true);
 printf("n[%s -> %s] Begin Time : %s, End Time : %s, Total Count : %s, CostTime: %s.n", __CLASS__, __FUNCTION__, $params['begin_date'], $params['end_date'], count($dataSource), ($endMicroTime - $startMicroTime));
 if (empty($dataSource)) {
 continue;
 }
 $endMicroTime = microtime(true);
 foreach ($dataSource as $_key => $_data) {
 $cnt++;
 if ($limit == $cnt) {
 # 刷新一下输出buffer,防止由于数据过多造成问题
 ob_flush();
 flush();
 $cnt = 0;
 }
 # 数据处理部分,根据自身业务自行定义,注意中文转码
 $salesStatisticsData['name'] = iconv('utf-8', 'GB18030', $salesStatisticsData['c_name']);
 fputcsv($fp, $salesStatisticsData);
 }
 }
 fclose($fp); # 每生成一个文件关闭
}
# 进行多文件压缩
$zip = new ZipArchive();
$number = rand(1000,9999);
$filename = $mark."_".$params['begin_date']."_".$params['end_date'] ."_".$number. ".zip";
$zip->open($filename, ZipArchive::CREATE); //打开压缩包
foreach ($fileNameArr as $file) {
 $zip->addFile($file, basename($file)); //向压缩包中添加文件
}
$zip->close(); //关闭压缩包
if (!file_exists($filename)) {
 // 首次执行检查生成的压缩文件是否存在失败,进行二次尝试。。。
 $endMicroTime = microtime(true);
 # 进行二次多文件压缩
 $number = rand(1000,9999);
 $filename = $mark."_".$params['begin_date']."_".$params['end_date'] ."_".$number. ".zip";
 if (file_exists($filename)) {
 unlink($filename);
 }
 $zip->open($filename, ZipArchive::CREATE); //打开压缩包
 foreach ($fileNameArr as $file) {
 $zip->addFile($file, basename($file)); //向压缩包中添加文件
 }
 $zip->close(); //关闭压缩包
}
if (file_exists($filename)) {
 $content = file_get_contents($filename);
 // 解决读取文件偶尔出现失败的问题,第一读出为空则尝试第二次读取
 $forNum = 0;
 while (!$content) {
 $forNum++;
 @$content = file_get_contents($filename);
 if ($forNum > 10) {
 break; // 防止出现异常情况导致死循环,最多重试10次
 }
 }
} else {
 $endMicroTime = microtime(true);
 # 删除临时文件,防止占用空间
 foreach ($fileNameArr as $file) {
 if (is_file($file)) {
 unlink($file);
 }
 }
 // 记录错误日志并且报警
 return false;
}
# 删除临时文件,防止占用空间
foreach ($fileNameArr as $file) {
 if (is_file($file)) {
 unlink($file);
 }
}

最后将生成好的文件存入文件系统,上传成功之后反转导出状态,前台检测到导出成功自动进行下载即可。



Tags:PHP 导出数据   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
公司目前有一个需求,需要对一个日增量在20万+数据量的数据表中的数据进行可自定义条件筛选的导出数据,该功能需要对多个部门进行开发使用,要保证功能可用的前提下,尽量优化体验...【详细内容】
2019-09-11  Tags: PHP 导出数据  点击:(146)  评论:(0)  加入收藏
▌简易百科推荐
序言:前段时间织梦因为版权的问题在网上闹得沸沸扬扬,也提醒了众多开发者选择cms上应该谨慎使用,今天给大家展示一款自己搭建的内容管理系统,不用担心版权的问题,而且非常容易维...【详细内容】
2021-11-30  小程序软件开发    Tags:管理系统   点击:(34)  评论:(0)  加入收藏
准备安装包(PHP: Hypertext Preprocessor)下载安装包以及组件wget https://www.php.net/distributions/php-8.0.0.tar.bz2wget https://github.com/phpredis/phpredis/archive...【详细内容】
2021-11-09  mimic96    Tags:PHP   点击:(40)  评论:(0)  加入收藏
golang context 很好用,就使用php实现了github地址 : https://github.com/qq1060656096/php-go-context context使用闭坑指南1. 将一个Context参数作为第一个参数传递给传入和...【详细内容】
2021-11-05  1060656096    Tags:PHP   点击:(41)  评论:(0)  加入收藏
一段数组为例:$list = array:4 [ 0 => array:7 [ "id" => 56 "mer_id" => 7 "order_id" => "wx163265961408769974" "is_postage" => 0 "store_name" => "奇...【详细内容】
2021-09-29  七七小影视    Tags:PHP   点击:(65)  评论:(0)  加入收藏
利用JS的CryptoJS 3.x和PHP的openssl_encrypt,openssl_decrypt实现AES对称加密解密,由于需要两种语言对同一字符串的操作,而CryptoJS 的默认加密方式为“aes-256-cbc”,PHP端也...【详细内容】
2021-09-16  李老师tome    Tags:对称加密   点击:(79)  评论:(0)  加入收藏
1、checkdate()验证格利高里日期即:日期是否存在。checkdate(month,day,year);month必需。一个从 1 到 12 的数字,规定月。day必需。一个从 1 到 31 的数字,规定日。year必需。...【详细内容】
2021-08-31  七七小影视    Tags:时间函数   点击:(80)  评论:(0)  加入收藏
对于各类开发语言来说,整数都有一个最大的位数,如果超过位数就无法显示或者操作了。其实,这也是一种精度越界之后产生的精度丢失问题。在我们的 PHP 代码中,最大的整数非常大,我...【详细内容】
2021-08-26  硬核项目经理    Tags:PHP   点击:(83)  评论:(0)  加入收藏
遵从所有教材以及各类数据结构相关的书书籍,我们先从线性表开始入门。今天这篇文章更偏概念,是关于有线性表的一个知识点的汇总。上文说过,物理结构是用于确定数据以何种方式存...【详细内容】
2021-07-19  硬核项目经理    Tags:线性表   点击:(94)  评论:(0)  加入收藏
一、开启IIS全部功能。二、部署PHP1.官网下载并解压PHP: https://windows.php.net/downloads/releases/2.将php.ini-development文件改为php.ini3.修改php.ini(1)去掉注释,并修...【详细内容】
2021-07-15  炘蓝火诗  今日头条  Tags:PHP环境   点击:(129)  评论:(0)  加入收藏
一、环境说明本文中使用本地VM虚机部署测试。OS:CentOS Linux release 7.8.2003 (Core)虚机配置:2核CPU、4G内存①系统为CentOS 7.8 x64最小化安装,部署前已完成系统初始化、...【详细内容】
2021-06-25  IT运维笔记  今日头条  Tags:PHP8.0.7   点击:(141)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条