17

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

$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()查询之后,我仍然会得到同样的错误。

我认为这应该一次只取一行;为什么它使用这么多内存?

4

1 回答 1

38

调用查询前内存使用量为 635384 字节。我猜查询会为每条记录分配块。

叮叮叮!

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

但就像 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

不这样做将导致错误。

于 2012-12-05T18:15:19.857 回答