【问题标题】:Processing a large result set with php使用 php 处理大型结果集
【发布时间】:2014-09-05 08:27:15
【问题描述】:

我的场景是这样的,我从 mysql 表中获取了一个巨大的数据集

$data = $somearray; //say the number of records in this array is 200000

我正在循环这些数据,处理一些功能并将这些数据写入一个 excel 文件

 $my_file = 'somefile.csv';
 $handle = fopen($my_file, 'w') or die('Cannot open file:  ' . $my_file); file
     for($i=0;$i<count($data);$i++){
         //do something with the data
         self::someOtherFunctionalities($data[$i]); //just some function    
         fwrite($handle, $data[$i]['index']); //here iam writing this data to a file
      }
 fclose($handle);

我的问题是循环内存耗尽......它显示“致命错误允许的内存大小为..”无论如何都可以在不耗尽的情况下处理这个循环

由于服务器限制,我无法像这样增加 php 内存限制

ini_set("memory_limit","2048M");

我不关心它需要的时间..即使需要几个小时..所以我做了set_time_limit(0)

【问题讨论】:

  • 不能批量读取 MySQL 数据或者逐行处理,而不是将整个集合保存到变量中吗?
  • 我也尝试过批处理...但它仍然挂起...有什么办法可以在每个循环结束时释放内存
  • 释放内存只需将变量设置为null,垃圾收集器应该处理内存。
  • 是否需要将所有数据提取到内存中?你不能一次取一行吗?
  • 您是否使用 PDO 来获取数据?

标签: php loops memory-management out-of-memory


【解决方案1】:

您的工作是线性的,您不需要加载所有数据。使用Unbuffered Query 也使用php://stdout(不要临时文件) 如果将此文件发送到httpClient。

<?php
$mysqli  = new mysqli("localhost", "my_user", "my_password", "world");
$uresult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);
$my_file = 'somefile.csv'; // php://stdout
$handle = fopen($my_file, 'w') or die('Cannot open file:  ' . $my_file); file

if ($uresult) {
   while ($row = $uresult->fetch_assoc()) {
   // $row=$data[i]
      self::someOtherFunctionalities($row); //just some function    
     fwrite($handle, $row['index']); //here iam writing this data to a file
   }
}
$uresult->close();
?>

【讨论】:

    【解决方案2】:

    您可以在 MySQL 查询中使用“LIMIT”吗?

    LIMIT 子句可用于限制 SELECT 语句返回的行数。 LIMIT 接受一个或两个数字参数,它们都必须是非负整数常量(使用准备好的语句时除外)。

    有两个参数,第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。初始行的偏移量为0(不是1):

    SELECT * FROM tbl LIMIT 5,10; # 检索第 6-15 行

    http://dev.mysql.com/doc/refman/5.0/en/select.html

    【讨论】:

      【解决方案3】:

      如果您不担心时间,一次取 1000 行,然后将行附加到文件末尾,例如。制作一个临时文件,在工作完成后移动和/或重命名。

      First select count(*) from table
        then for($i = 0; i < number of row; i = i + 1000){
        result = SELECT * FROM table LIMIT i,1000; # Retrieve rows 6-15
        append to file = result
      }
      move and rename the file
      

      这是非常元代码,但该过程应该可以工作

      【讨论】:

      • 查询需要order by,否则不保证会选择下一批。它还假设数据没有变化。
      • 随意使用编辑按钮来改进我的建议,正如我所说,这只是一个关于如何做到这一点的列表形式,而不是一个工作示例。
      猜你喜欢
      • 2012-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-31
      • 2014-07-11
      相关资源
      最近更新 更多