php百万数据通过脚本文件写入csv

需求:百万数据写入csv。
框架:N多年前老框架,百度都搜不到了,所以写法趋近原生

分析:数据量过大,不能用浏览器请求写入csv下载,所以写个脚本调取

伪代码:

//xxx - 根据自己项目替换
//调取脚本文件
exec(xxx);

//脚本文件
//设置执行时间和内存
set_time_limit(0);
ini_set('memory_limit', '128M');
//循环获取
$id = 0;
$data = 'xxx'.'\n';//表头
while(true){
    //SQL
    $list = xxx WHERE id > $id ORDER BY id ASC LIMIT 10000; //每次取1w防止数据库压力大,根据sql来,我这个有联表,
    if(empty($list)){
        break;
    }
    foreach($list as $row){
        $data .= '"' . $row['xxx'] . '",';
        $data .= "\n";
        $id = $row['id'];//更新最大id
    }
    //追加写入csv
    file_put_contents('xxx', mb_convert_encoding($data, 'gbk'),FILE_APPEND);
    unset($data);//基础不好不确定初始化能不能清内存就先unset了
    $data = '';//初始化
}

本质上就是分批写入,刚开始试验的时候是打算不把file_put_contents写在循环里的,后来发现数据量大的时候,几十万数据$data内存就超了:laughing:另外如果超百万数据的话需要做分文件导出,excel不支持打开超过1048576行,理论上就是加个$all_count参数计当前查询的总数,超过百万再加新文件。

如果有更好的方法,或者代码优化部分欢迎讨论。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 15

可以用yield会比较节省内存

1年前 评论
CodeUndefined (作者) 1年前
伽蓝幻梦 (楼主) 1年前
CodeUndefined (作者) 1年前
CodeUndefined (作者) 1年前
伽蓝幻梦 (楼主) 1年前
Jyunwaa
  1. 单引号包围换行符\n没看明白。
  2. 无须unset($data),初始化就会释放内存。
  3. 关于yield是否节省内存,我认为在该例子中答案是。已经一次性取出一万条,并且载入内存,这可是一个实实在在的数组结构,而后续的$data不过是一个比较长的字符串,此时再来yield实属滑稽。
1年前 评论
CodeUndefined 1年前
CodeUndefined 1年前
renxiaotu 1年前
ichynul 1年前

fputcsv 更好

1年前 评论
伽蓝幻梦 (楼主) 1年前
jiangjun

每次一万数据,取少了。当时看你数据库配置,把memory_limit,和数据库条数往上加,100万的,可以做到2次或3次查询数据库就能导出来。如果并发很小,比如这是后台应用(服务器资源充足),一次就能取100万。

1年前 评论

file_put_contents 在循环中的性能较差,可以把其看作是 fopen、fwrite、fclose 的包装。

如果你的内容中不存在需要转义字符的话,可以不考虑使用 fputcsv ,因为这个的效率也不是很高,直接使用 fwrite,不过这个确实好用 ~

转换编码为 gbk 不是必须的,建议直接在文件头添加 UTF-8 BOM ,这样 Microsoft Excel 就可以正确显示了。

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!