fputrunning在创建较大文件时内存不足


fputrunning out of memory during creation of larger files

我有时会根据数据库信息创建大型csv文件,供用户下载-100k或更多行。在一些较大的文件上创建csv时,我似乎遇到了内存问题。下面是我目前如何处理csv创建的一个例子。

有办法解决这个问题吗?最初有3200万字节,后来改为6400万字节,但仍然存在问题。

//columns array
$log_columns = array(
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9'
    );
//results from the db
$results = $log_stmt->fetchAll(PDO::FETCH_ASSOC);
$log_file = 'test.csv';
$log_path = $_SERVER['DOCUMENT_ROOT'].'/../user-data/'.$_SESSION['user']['account_id'].'/downloads/';
// if location does not exist create it
if(!file_exists($log_path)) 
{
    mkdir($log_path, 0755, true);
}
// open file handler
$fp = fopen($log_path.$log_file, 'wb');
// write the csv column titles / labels
fputcsv($fp, $log_columns);
//are there any logs?
if($results)
{
    //write the rows
    foreach($results as $row)
    {
        //rows array
        $log_rows = array(
            $row['1'],
            $row['2'],
            $row['3'],
            $row['4'],
            $row['5'],
            $row['6'],
            $row['7'],
            $row['8'],
            $row['9']
        );
        //write the rows
        $newcsv = fputcsv($fp, $log_rows);
    }//end foreach
}
// there were no results so just return an empty log
else
{
    $newcsv = fputcsv($fp, array('No results found.') );
}
//close handler 
fclose($fp);
// if csv was created return true
if($newcsv)
{       
    return true;        
}

更新:

使用while循环和fetch而不是foreach和fetchAll仍然会产生内存错误。

while($result = $log_stmt->fetch(PDO::FETCH_ASSOC))

如果我一次只加载一行,那怎么可能呢?

更新2:

我已经使用memory_get_usage(); 进一步追踪到while循环

echo (floor( memory_get_usage() / 1024) ).' kb<br />';

在while循环开始之前,结果是4658kb,然后对于while循环的每次迭代,它每2-3个循环增加1kb,直到它达到允许的32748kb最大内存。

我能做些什么来解决这个问题?

更新3:

今天玩得更多。。。这种工作方式对我来说没有多大意义——我只能假设这是php的GC的一种奇怪行为。

场景1:我的查询获取所有80k行,并使用while循环输出它们。在获取查询后,使用的内存约为4500kb,然后在循环中输出的每两到三行增加1kb。内存并没有像以前那样被释放,而且在某个时刻没有足够的内存就会崩溃。

while($results = $log_stmt->fetch(PDO::FETCH_ASSOC))
{
    echo $results['timestamp'].'<br/>';
}

场景2:我的查询现在是循环的,一次得到1000行,其中每个行都有一个循环输出。当它循环并在没有内存问题的情况下完成整个输出时,内存最大值为400k。

对于这个例子,我只使用了80次计数器,因为我知道有超过80k行要检索。事实上,很明显,我不得不采取不同的做法。

$t_counter = 0;
while($t_counter < 80)
{
    //set bindings
    $binding = array(
        'cw_start' => $t_counter * 1000,
             //some other bindings...
    );
    $log_stmt->execute($binding);
echo $t_counter.' after statement '.floor( memory_get_usage() / 1024 ).' kb<br />';
    while($results = $log_stmt->fetch(PDO::FETCH_ASSOC))
    {
        echo $results['capture_timestamp'].'<br/>';
    }
echo $t_counter.' after while'.floor( memory_get_usage() / 1024 ).' kb<br />';
$t_counter++;
}

所以我想我的问题是,为什么第一个场景的内存使用量不断增加,却什么都没有发布?在while循环中没有新的变量,所有的东西都被"重用"了。完全相同的情况发生在另一个循环中的第二个场景中。

fetchAll获取所有记录,这些记录不仅查询它并用fetch进行while循环,而且不需要在内存中加载所有结果集。

http://php.net/manual/en/pdostatement.fetch.php

然后我认为您应该尝试以位读取文件。读取它们并将其附加到一个csv文件中,这样可以在处理过程中释放内存。您可以进行计数(*),但尝试在多个集合之前找到总计数

我自己一直在使用php的csv,我甚至把它用作数据库系统(nosql)尝试

用于读取的csv代码<?php
$CSVfp = fopen("filename.csv", "r"); if($CSVfp !== FALSE) { $con=1; while(! feof($CSVfp)) { do something }?>

**csv code for writting **
<?php
$list = array
(
"edmond,dog,cat,redonton",
"Glenn,Quagmire,Oslo,Norway",
);$file = fopen("filename.csv","w");foreach ($list as $line)      
{fputcsv($file,explode(',',$line));}fclose($file); ?>