导出百万级数据

记录一下(初步实现)

<?php //让程序一直运行  set_time_limit(0); //设置程序运行内存  ini_set('memory_limit', '128M'); $fileName = '商品导出数据'; 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, ['商品', '价格', '库存']); //链接数据库 $dsn = "mysql:host=127.0.0.1;port=3306;dbname=db_www;charset=utf8"; $pdo = new PDO($dsn, 'root', ''); $step = 100; //循环次数  $nums = 10000; //每次导出数量  for ($i = 0; $i < $step; $i++) { $start = $i * 10000; $sql = "SELECT product_code,price,qty FROM `products` ORDER BY `id` LIMIT {$start},{$nums}"; $productMysql = $pdo->query($sql); $result = $productMysql->fetchAll(PDO::FETCH_ASSOC); foreach ($result as $item) { fputcsv($fp, $item); } //每1万条数据就刷新缓冲区  ob_flush(); flush(); }

根据大佬们的建议修整后为

<?php //让程序一直运行 set_time_limit(0); //设置程序运行内存 ini_set('memory_limit', '128M'); $fileName = '商品导出数据'; 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, ['商品', '价格', '库存']); // 链接数据库 $dsn = "mysql:host=127.0.0.1;port=3306;dbname=db_www;charset=utf8"; $pdo = new PDO($dsn, 'root', ''); $nums = 10000; // 每次查询的数量 $lastId = 0; // 上一批数据的最后一个ID do { $sql = "SELECT product_code, price, qty FROM `products` WHERE id > :lastId ORDER BY `id` LIMIT :nums"; $stmt = $pdo->prepare($sql); $stmt->bindParam(':lastId', $lastId, PDO::PARAM_INT); $stmt->bindParam(':nums', $nums, PDO::PARAM_INT); $stmt->execute(); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($result as $item) { fputcsv($fp, $item); } $lastId = $result[count($result) - 1]['id']; ob_flush(); flush(); } while (count($result) > 0); fclose($fp); 
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 8

可否再优化一下,百万数据,使用chunk分块,例如分为10块,并且使用定时任务,这样效率会不会更高一些?for循环里使用查询,这样的效率肯定是不高的。

$total = 1000000; $times = 10; YouModel::chunk($total/$$times, function (Collection $youmodels) { foreach ($youmodels as $model) { // ... } }); 
2年前 评论

LIMIT {$start},{$nums} 这个用法到后面会越来越慢,可以换成记录当前循环的最大ID,每次取大于该ID的10000条数据。

2年前 评论
辰曦 (楼主) 2年前

xlswriter可以试试

2年前 评论

如果不要求实时性的话直接定时任务异步导出

2年前 评论

用php导出复杂业务百万数据级要几十秒, 换成go的协程4秒 :smile:

2年前 评论
misyuan 2年前
郭扑克 2年前

未填写
文章
1
粉丝
1
喜欢
1
收藏
2
排名:2270
访问:731
私信
所有博文
社区赞助商