通过单个PDO查询意外地达到了PHP内存限制?

时间:2012-12-05 16:42:55

标签: php mysql memory pdo

我有一个非常简单的查询,看起来像:

$result = $pdo->query('SELECT * FROM my_table');

foreach($result as $r) {
    // do some stuff
}

但是当我运行这个时,我收到以下错误:

  

致命错误:第15行的/path/to/myfile.php中允许的内存大小为134217728个字节(尝试分配32个字节)

“第15行”是$pdo->query行。

如果我在查询后放die(),我仍然会收到相同的错误。

我以为这只能在一次获取一行;它为什么要使用这么多内存?

1 个答案:

答案 0 :(得分:28)

  

调用查询之前,内存使用量为635384字节。我猜测查询是按块分配给每条记录的。

丁丁丁!

连接到MySQL时,PHP喜欢使用buffered queries。无论您使用何种方法进行连接,都是如此。使用缓冲查询时,会立即获取整个结果集,而不是在您询问时获取。这通常通常对性能有好处,因为往返次数较少。

但是像PHP中的所有东西一样,有一个问题。如缓冲页面所述:

  

当使用libmysql作为库时,PHP的内存限制将不计算用于结果集的内存,除非将数据提取到PHP变量中。使用mysqlnd时,占用的内存将包括完整的结果集。

你正在使用PHP 5.3,这意味着你很有可能使用mysqlnd。

您需要在此处关闭缓冲查询。在MySQL的每个PHP接口中都有不同的做法:

  • 对于PDO,您需要将PDO::MYSQL_ATTR_USE_BUFFERED_QUERY属性设置为false
  • 对于mysqli,您需要将MYSQLI_USE_RESULT常量传递给query方法。
  • 对于mysql,您需要拨打mysql_unbuffered_query而不是mysql_query

页面上有完整的详细信息和示例。

大胖无缓冲查询问题!

必须正确关闭语句句柄并释放结果集,然后再发出另一个查询:

  • 在PDO中,这意味着在语句句柄上调用closeCursor
  • 在mysqli中,这意味着在语句句柄上调用free_result或在结果句柄上调用free,具体取决于您正在使用的内容。
  • 在mysql中,这意味着调用mysql_free_result

如果不这样做,将导致错误。