使用PHP / Drupal处理大型数据集

时间:2010-03-19 12:27:45

标签: php drupal memory-management resultset

我有一个报告页面,用于处理数据库表中约700,000条记录。我可以使用分页在网页上显示此内容以分解结果。但是,我导出到PDF / CSV函数依赖于立即处理整个数据集,而我的内存限制大约为250k行。

我觉得增加内存限制并不舒服,而且我没有能力使用MySQL的保存到outfile中来提供预先生成的CSV。但是,我无法真正看到使用Drupal提供大型数据集的方法:

$form = array();
$table_headers = array();
$table_rows = array();
$data = db_query("a query to get the whole dataset");
while ($row = db_fetch_object($data)) {
    $table_rows[] = $row->some attribute;
}

$form['report'] = array('#value' => theme('table', $table_headers, $table_rows);
return $form;

有没有办法解决基本附加到巨大数组阵列的问题?目前我还没有看到如何通过Drupal提供任何有意义的报告页面。

由于

7 个答案:

答案 0 :(得分:4)

有了这么大的数据集,我会使用Drupal的Batch API,它允许将时间密集型操作分成批次。它对用户来说也更好,因为它会给他们一个进度条,指示操作需要多长时间。

通过打开临时文件启动批处理操作,然后在每个新批处理中向其添加新记录,直到完成为止。最后一页可以进行最终处理,以将数据作为cvs或转换为PDF。你可能也想在后面添加一些清理。

http://api.drupal.org/api/group/batch/6

答案 1 :(得分:1)

如果要生成PDF或CSV,则不应使用Drupal本机功能。如何写入while循环中的输出文件?这样,在给定时间内只有一个结果集在内存中。

答案 2 :(得分:0)

目前,您将所有内容存储在数组$table_rows

当你从数据库中读取报告时,你是否不能刷新报告的至少部分(例如,每隔那么多行)以释放一些内存?我不明白为什么它应该只能一次写入csv。

答案 3 :(得分:0)

  

我觉得增加内存限制感觉不舒服

增加内存限制并不意味着每个php进程都会使用该内存量。但是你可以用自定义内存限制执行php的cli版本 - 但这也不是正确的解决方案......

  

我没有能力使用MySQL的保存到outfile中来提供预先生成的CSV

然后不要将它全部保存在数组中 - 当从数据库中获取它时,将每一行写入输出缓冲区(IIRC,整个结果集缓存在有限的php内存之外)。或者直接将其写入文件,然后在文件完成并关闭时进行重定向。

下进行。

答案 4 :(得分:0)

您应该使用pager_query包含分页,并将结果分成每页50-100。这应该会有很大帮助。你说你想使用分页,但我没有在代码中看到它。

检查出来:http://api.drupal.org/api/function/pager_query/6

答案 5 :(得分:0)

要记住的另一件事是,在PHP5(5.3之前)中,将数组分配给新变量或将其传递给函数复制数组并且不创建引用。您可能正在创建相同数据的许多副本,如果没有未设置或超出范围,则无法对其进行垃圾回收以释放内存。在可能的情况下,使用引用对原始数组执行操作可以节省内存

function doSomething($arg){
  foreach($arg AS $var)
    // a new copy is created here internally: 3 copies of data exist
    $internal[] = doSomethingToValue($var);
  return $internal;
  // $arg goes out of scope and can be garbage collected: 2 copies exist
}
$var = array();
// a copy is passed to function: 2 copies of data exist
$var2 = doSomething($var);
// $var2 will be a reference to the same object in memory as $internal, 
//  so only 2 copies still exist

如果将$ var设置为函数的返回值,则可以对旧值进行垃圾收集,但直到赋值后才能进行垃圾收集,因此短时间内仍需要更多内存

function doSomething(&$arg){
  foreach($arg AS &$var)
    // operations are performed on original array data: 
    // only two copies of an array element exist at once, not the whole array
    $var = doSomethingToValue($var);  
  unset($var); // not needed here, but good practice in large functions
}
$var = array();
// a reference is passed to function: 1 copy of data exists
doSomething($var);

答案 6 :(得分:0)

我处理如此庞大的报告的方法是使用php cli / Java / CPP / C#生成它们(即CRONTAB)+使用mysql所拥有的无缓冲查询选项。 在磁盘上完成文件/报告创建后,您可以给它一个链接......