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

mpe*_*pen 15 php mysql memory pdo

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

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

foreach($result as $r) {
    // do some stuff
}
Run Code Online (Sandbox Code Playgroud)

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

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

"15号线"就$pdo->query行了.

如果我把die()查询后,我仍然得到相同的错误.

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

Cha*_*les 29

在调用查询之前,内存使用量为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

如果不这样做将导致错误.

  • 老实说,我从未尝试过,因为结合无缓冲和fetchAll听起来非常愚蠢. (3认同)
  • 如果你使用 `fetchAll` 或遍历整个结果集,我认为你不需要调用 `closeCursor`;仅当您还有未提取的行时。无论如何,很好的答案!再次感谢。 (2认同)