缓冲和非缓冲查询

查询默认情况下使用缓冲模式。这意味着查询结果会立即从 MySQL 服务器传输到 PHP,然后保存在 PHP 进程的内存中。这允许执行额外的操作,例如计算行数,以及移动(查找)当前结果指针。它还允许在处理结果集时对同一个连接发出进一步的查询。缓冲模式的缺点是,较大的结果集可能需要相当多的内存。内存将一直占用,直到所有对结果集的引用都被取消设置或结果集被显式释放,这将在请求结束时自动发生。术语“存储结果”也用于缓冲模式,因为整个结果集都一次性存储起来。

注意:

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

非缓冲的 MySQL 查询会执行查询,然后等待从 MySQL 服务器获取数据。这在 PHP 端使用更少的内存,但会增加服务器的负载。除非从服务器获取了完整的结果集,否则无法通过同一个连接发送进一步的查询。非缓冲查询也可以称为“使用结果”。一旦结果集中所有的行都被获取,结果集就消失了,并且不能再迭代。

根据这些特性,只有在预期到一个将被顺序处理的大型结果集时,才应该使用非缓冲查询。非缓冲查询包含一些陷阱,使得使用它们更加困难,例如,结果集中的行数在获取最后一行之前是未知的。缓冲查询是处理结果集更容易和更灵活的方式。

由于缓冲查询是默认值,因此下面的示例将演示如何在每个 API 中执行非缓冲查询。

示例 #1 非缓冲查询示例:mysqli

<?php
$mysqli
= new mysqli("localhost", "my_user", "my_password", "world");
$unbufferedResult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);

foreach (
$unbufferedResult as $row) {
echo
$row['Name'] . PHP_EOL;
}
?>

示例 #2 非缓冲查询示例:pdo_mysql

<?php
$pdo
= new PDO("mysql:host=localhost;dbname=world", 'my_user', 'my_password');
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

$unbufferedResult = $pdo->query("SELECT Name FROM City");
foreach (
$unbufferedResult as $row) {
echo
$row['Name'] . PHP_EOL;
}
?>
添加注释

用户贡献的注释 1 条注释

1
polygon dot co dot in at gmail dot com
1 年前
缓冲和非缓冲查询可用于有限数量的记录。

例如,在使用缓冲方式实现查询的下载 CSV 时,在缓冲超过 30,000 条记录时会出现内存限制问题。

类似地,对于非缓冲,负载切换到数据库服务器。

如下所示,可以通过以下方式减少 Web(缓冲)和 MySQL(非缓冲)服务器上的这种负载,以支持 30,000+ 条记录的下载 CSV。

<?php
// Shell 命令。
$shellCommand = 'mysql '
. '--host='.escapeshellarg($hostname).' '
. '--user='.escapeshellarg($username).' '
. '--password='.escapeshellarg($password).' '
. '--database='.escapeshellarg($database).' '
. '--execute='.escapeshellarg($sql).' '
. '| sed -e \'s/"/""/g ; s/\t/","/g ; s/^/"/g ; s/$/"/g\'';

// CSV 头部
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename={$csvFilename}");
header("Pragma: no-cache");
header("Expires: 0");

// 通过 shell 执行命令并回显整个输出作为字符串
echo shell_exec($shellCommand);
?>

对于 sed 正则表达式将会有少量的 CPU 消耗。
To Top