简体   繁体   English

从MySQL提取大型数据集时PHP中的内存泄漏

[英]Memory leak in PHP when fetching large dataset from MySQL

When I execute the following code for a user table of about 60,000 records: 当我为大约60,000条记录的用户表执行以下代码时:

mysql_connect("localhost", "root", "");
mysql_select_db("test");

$result = mysql_query("select * from users");

while ($row = mysql_fetch_object($result)) {
  echo(convert(memory_get_usage(true))."\n");
}


function convert($size) {
  $unit=array('b','kb','mb','gb','tb','pb');
  return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
}

I get the following error: 我收到以下错误:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes)

Any thoughts on how to avoid having the script take up additional memory with each pass through the loop? 是否有关于如何避免脚本在每次循环中占用额外内存的想法? In my actual code I'm trying to provide a CSV download for a large dataset, with a little PHP pre-processing. 在我的实际代码中,我试图为大型数据集提供CSV下载,并进行一些PHP预处理。

Please don't recommend increasing PHP's memory limit--it's a bad idea and, more importantly, will still create an upward bound on how large a dataset can be processed with this technique. 请不要建议增加PHP的内存限制-这是一个坏主意,更重要的是,仍然会限制使用此技术可以处理多大数据集。

I'm not 100% sure if this will solve your problem, but have you considered using PDO ? 我不确定100%是否可以解决您的问题,但是您是否考虑过使用PDO It has several advantages; 它具有几个优点; you can read more about them here . 您可以在此处阅读有关它们的更多信息。 If you do go in that direction, there is a similar question about memory usage here . 如果你往那个方向,有关于内存使用一个类似的问题在这里

mysql_query buffers the entire result set into php memory. mysql_query将整个结果集缓冲到php内存中。 This is convenient and generally very fast, but you're experiencing a drawback to it. 这很方便并且通常非常快,但是您遇到了一个缺点。

mysql_unbuffered_query () exists. mysql_unbuffered_query ()存在。 It doesn't grab the entire result set all at once. 它不会一次获取全部结果集。 It grabs little pieces at a time when you fetch rows from the result set. 当您从结果集中获取行时,它一次抓取一些小片段。

I have had a similar problem. 我有类似的问题。 What I did to get it to work was to create a temporary file (you can use hash or something similar to keep a record of the name). 我要做的就是创建一个临时文件(您可以使用哈希或类似的方法来保存名称记录)。

  • Pull 10,000 rows and put them into a file (temp). 拉10,000行并将其放入文件(临时)。 Put it into a temp csv file. 将其放入临时csv文件中。
  • Reload page (using header with specific parameters / session) 重新加载页面(使用带有特定参数/会话的标头)
  • Pull another 10,000 rows and append it to a file. 再拉10,000行并将其附加到文件中。
  • When you reach end of the table - buffer file to user. 当您到达表的末尾时-缓冲文件给用户。

Go like that in circles until you got it all. 像这样绕圈走,直到掌握全部。 I had to do this work around for two reasons, 我不得不做此工作有两个原因,

  1. Timeout 超时
  2. Out of memory error. 内存不足错误。

Drawbacks of this method is that it requires many HTTP calls to get data. 该方法的缺点是它需要许多HTTP调用才能获取数据。 Also in the mean time there could be rows that have changed etc. It is a pretty "dirty" way of doing it. 同时,也可能有行已更改等。这是一种非常“肮脏”的方式。 I'm yet to find something that works better. 我还没有找到更好的方法。 Hope that helps. 希望能有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM