使用PHP / MySQL导出大型CSV数据的最佳方法是什么?

时间:2014-04-11 22:04:56

标签: php mysql ajax export-to-csv large-data

我正在开发一个项目,我需要从包含近10k行的数据库中提取数据,然后将其导出为CSV。我尝试了正常的方法来下载CSV,但即使我们已经将memory_limit设置为256MB,我总是会遇到内存限制问题。

如果您遇到任何问题,请分享您对最佳解决方案或方法的看法。

真的很感激你的想法。

这是我的实际代码:

$filename = date('Ymd_His').'-export.csv';

//output the headers for the CSV file
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Description: File Transfer');
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename={$filename}");
header("Expires: 0");
header("Pragma: public");

//open the file stream
$fh = @fopen( 'php://output', 'w' );

$headerDisplayed = false;

foreach ( $formatted_arr_data_from_query as $data ) {
    // Add a header row if it hasn't been added yet -- using custom field keys from first array
    if ( !$headerDisplayed ) {
        fputcsv($fh, array_keys($ccsve_generate_value_arr));
        $headerDisplayed = true;
    }

    // Put the data from the new multi-dimensional array into the stream
    fputcsv($fh, $data);
}

// Close the file stream
fclose($fh);

4 个答案:

答案 0 :(得分:2)

如果你真的必须用PHP进行处理,你需要使用MYSQL的limit命令来获取你的数据子集。每次只抓取一定数量的行,将它们写入文件然后获取下一组。

您可能需要在查询循环中的一些变量上运行unset()。关键是不要在内存中同时存在太多巨大的arrarys。

如果您正在抓取整个合并的表格,请按插入日期升序对其进行排序,以便第二次抓取将获得更新的项目。

答案 1 :(得分:1)

正如本评论中所解释的:https://stackoverflow.com/a/12041241/68567使用mysqldump可能是最好的选择。如果需要,您甚至可以使用exec()命令通过php执行此操作,如下所述:php exec() - mysqldump creates an empty file

答案 2 :(得分:0)

  • 从查询结果集中单独读取每个数据行
  • 直接写入php:// output
  • 然后阅读下一行等;

而不是构建任何大型数组或在内存中构建csv

答案 3 :(得分:0)

简短说明:将数百行的数据包导出到CSV重用变量,因此内存压力将保持较低。你不能将一个完整的mysql表抛出一个数组(然后是CSV文件),这是主要的问题

详细说明:尝试使用此列表导出一个包含列名的大表(我使用过它,效果很好,也可以进行改进,压缩和优化,但稍后):

  1. 打开CSV文件(标题,fopen等)
  2. 使用列名称定义一个数组:fputcsv($f, $line, $delimiter);
  3. 获取您想要的ID列表(不是整行,只有ID):SELECT id FROM table WHERE condition ORDER BY your_desired_field ASC - >在这里你有$ ids
  4. $perpage=200; // how many lines you export to csv in a pack;
  5. for ($z=0;$z < count($ids);$z+=$perpage) { $q="SELECT * FROM table WHERE same_condition ORDER BY your_desired_field ASC LIMIT ".$perpage." OFFSET ".$z // important: use the same query as for retrieving ids, only add limit/offset. Advice: use ORDER BY, don't ignore it, even if you do not really need it; $x=[execute query q] for($k=0;$k <count($x);$k++) { $line=array ($x[$k]->id, $x[$k]->field1, $x[$k]->field2 ..); fputcsv($f, $line, $delimiter); } } // end for $z
  6. 关闭CSV
  7. 因此,您将循环遍历整个结果表,获取200行并将其写入CSV,这将等待打开,直到您写完所有行。您需要的所有内存都是200行,因为您将重写该变量。我相信它可以以更好的方式完成,但对我来说需要几个小时,并没有找到解决方案;此外,它受我的架构和应用程序需求的影响,这就是我选择此解决方案的原因。