如何使用Symfony将数据导出到CSV而不会耗尽内存?

时间:2012-06-08 18:21:28

标签: php csv symfony1 symfony-1.4 export-to-csv

我已经遇到过这个问题了几次。

我有一段将数据导出到CSV的代码。我正在使用的方法将结果集传递给模板,模板循环遍历结果,回显字段。

在行动中:

$this->result = ObjectPeer::doSelect($criteria);

在模板中:

foreach ($result as $row)
{
  echo $row->getValue1().','.$row->getValue2().','.$row->getValue3()...
}

但是,如果结果集很大,我将耗尽内存:

 [error] PHP Fatal error:  Allowed memory size of 268435456 bytes exhausted (tried to allocate 1556481 bytes) in exportSuccess.php on line 13, referer: https://mysite.com/module

该过程使用超过250 mb,但它创建的文件只有~2 mb。 我可以增加php.ini为进程提供的内存量,但我不愿意。如果出口足够大,我有点怀疑我能够给它足够的记忆。

我已经阅读了一些与此相似的其他案例,建议在每次回显后取消$ row。这在我的案例中不起作用。

我认为有一种方法可以对此查询进行分块并仍构建整个文件 - 任何人都可以推荐或指向我一个明确的教程吗?

2 个答案:

答案 0 :(得分:1)

根据您要检索的元素数量(例如:getValue1getValue2等),您可以保留结果in a different way

$stmt = ObjectPeer::doSelectStmt($m_criteria);
while ($row = $stmt->fetch(PDO::FETCH_NUM))
{
  echo $row[0];
}

此外,您可以使用doSelectRS检查其他解决方案:

$rs = ObjectPeer::doSelectRS($criteria);
$rs->setFetchMode(ResultSet::FETCHMODE_ASSOC);

while($rs->next())
{
  $records = $rs->getRow();
  // then use $records['key'] to retrieve information
}

你可以检查的其他事情很少。关于memory leak form Propel的法语论文。

答案 1 :(得分:-1)

这是写入csv文件的基本思路。这不显示与数据库的连接,但事后是一切,并确保在最后关闭连接。

$filename = 'c:\whatever.csv';

$fp = fopen($filename, "w")  or die(mysql_error());
echo "Connected to ".$filename." <br>";


$res = mysql_query("SELECT *
FROM $table1 

WHERE Something
");

// fetch a row and write the column names out to the file
echo mysql_error();
$row = mysql_fetch_assoc($res);
$line = "";
$comma = "";
foreach($row as $name => $value) {
$line .= $comma . '"' . str_replace('"', '""', $name) . '"';
$comma = ",";
}
$line .= "\n";
fputs($fp, $line);

// remove the result pointer back to the start
mysql_data_seek($res, 0);

// and loop through the actual data
echo mysql_error();
while($row = mysql_fetch_assoc($res)) {

$line = "";
$comma = "";
foreach($row as $value) {
    $line .= $comma . '"' . str_replace('"', '""', $value) . '"';
    $comma = ",";

}
$line .= "\n";
fputs($fp, $line);
}