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

可以用yield会比较节省内存

1年前 评论
CodeUndefined (作者) 1年前
伽蓝幻梦 (楼主) 1年前
CodeUndefined (作者) 1年前
CodeUndefined (作者) 1年前
伽蓝幻梦 (楼主) 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年前 评论

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