意外达到单个 PDO 查询的 PHP 内存限制?

2022-08-30 20:51:25

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

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

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

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

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

“15号线”是这条线。$pdo->query

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

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


答案 1

在调用查询之前,内存使用量为 635384 个字节。我猜查询以块为单位为每个记录分配。

叮叮叮

连接到MySQL时,PHP喜欢使用缓冲查询。无论您使用哪种方法进行连接,都是如此。使用缓冲查询时,将立即提取整个结果集,而不是在询问时提取。这通常有利于性能,因为往返行程较少。

但就像PHP中的所有内容一样,有一个陷阱。如缓冲页面上所述:

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

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

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

  • 对于 PDO,您需要将该属性设置为 。PDO::MYSQL_ATTR_USE_BUFFERED_QUERYfalse
  • 对于 mysqli,您需要将常量传递给查询方法。MYSQLI_USE_RESULT
  • 对于 mysql,您需要调用而不是 .mysql_unbuffered_querymysql_query

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

大胖子无缓冲查询陷阱 !

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

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

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


答案 2

推荐