编写一个非常大的CSV文件来自PHP的DB输出

时间:2011-05-16 17:45:36

标签: php mysql csv

我每秒都会收集一份传感器数据库。客户希望能够以CSV格式下载12小时的块 - 这一切都已完成。

输出很遗憾不是直接数据,需要在创建CSV之前进行处理(部件在数据库中存储为JSON) - 所以我不能只是转储表。

因此,为了减少负载,我认为第一次下载文件时,我会将其缓存到磁盘,然后再有任何请求只下载该文件。

如果我不尝试编写它(使用file_put_contents,FILE_APPEND),并且只是回显每一行就可以了,但是编写它,即使我给脚本512M它也会耗尽内存。

所以这可行

while($stmt->fetch()){
    //processing code
    $content = //CSV formatting
    echo $content;
}

这不是

while($stmt->fetch()){
    //processing code
    $content = //CSV formatting
    file_put_contents($pathToFile, $content, FILE_APPEND);
}

似乎我甚至认为我在每一行调用file_put_contents,它将它全部存储到内存中。

有什么建议吗?

2 个答案:

答案 0 :(得分:0)

问题是file_put_contents试图一次性转储整个东西。相反,你应该在你的格式中循环并使用fopen,fwrite,fclose。

while($stmt->fetch()){
    //processing code
    $content[] = //CSV formatting
    $file = fopen($pathToFile, a);
    foreach($content as $line)
    {
        fwrite($file, $line);
    }
    fclose($file);
}

这将限制在任何给定时间尝试在数据中抛出的数据量。

答案 1 :(得分:0)

我完全同意一次写一行,你永远不会有这样的内存问题,因为一次只有1行加载到内存中。我有一个相同的应用程序。然而,我用这种方法发现的一个问题是该文件需要永远完成写入。所以这篇文章是为了备份已经说过的内容,还要求大家就如何提高速度提出意见?例如,我的系统根据抑制文件清理数据文件,因此我一次读取一行并在抑制文件中查找匹配项,如果未找到匹配项,则将该行写入新清理的文件中。一个50k的行文件需要大约4个小时才能完成,所以我希望找到一个更好的方法。我已经尝试了几种方法,此时我将整个抑制文件加载到内存中,以避免我的主读取循环必须在抑制文件中的每一行运行另一个循环,但即使这样仍需要几个小时。 / p>

因此,逐行是管理系统内存的最佳方式,但我希望获得50k行文件的处理时间(行是电子邮件地址,名字和姓),以便完成运行如果可能的话,不到30分钟。

fyi:抑制文件的大小为16,000 kb,而memory_get_usage()告诉脚本使用的总内存大约为35兆。

谢谢!