要实现PHP查询数据库时结果逐行实时输出,需同时满足:使用无缓冲查询(MySQLi用mysqli_real_query+mysqli_use_result,PDO需禁用缓冲并设游标为非缓冲)、禁用PHP及Web服务器输出缓冲、前端用fetch流式读取。

PHP 查询数据库时如何让结果逐行实时输出
默认情况下,mysqli_query() 或 PDO::query() 会等整张结果集全部从 MySQL 返回并缓冲到 PHP 内存中,才开始处理 —— 这意味着用户得等到最后一条记录查完才能看到任何输出。要实现“边查边显示”,关键不是换函数,而是控制查询方式 + 输出缓冲 + 客户端接收逻辑。
- 必须用无缓冲查询(unbuffered query):MySQLi 要调用
mysqli_use_result()或使用MYSQLI_USE_RESULT标志;PDO 则需在query()前设置PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false - 禁用 PHP 输出缓冲:
ob_end_flush()+flush()每次 echo 后都要跟上,且确保 Web 服务器(如 Nginx/Apache)没开启额外的响应缓冲(例如 Nginx 的fastcgi_buffering on会吃掉实时流) -
浏览器端需要能持续接收流式响应:HTML 中建议加
或EventSource,纯echo+ 刷新页面不可靠(HTTP/1.1 无流式语义保障)
MySQLi 无缓冲查询配合实时 flush 的写法
用 mysqli_real_query() + mysqli_use_result() 是最稳妥的组合,它不把整张结果集拉进内存,而是按需从 socket 读取下一行。
// 示例:逐行输出用户列表,不等全部查完
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
$mysqli->real_query("SELECT id, name FROM users WHERE status=1");
$result = $mysqli->use_result();
while ($row = $result->fetch_assoc()) {
echo json_encode($row) . "\n";
ob_flush();
flush(); // 必须成对调用
usleep(10000); // 可选:模拟处理延迟,便于观察流式效果
}
$result->free();
注意:mysqli_query() 不支持无缓冲模式,硬要用会报错或自动转为缓冲查询 —— 所以不能写 $mysqli->query("...")。
PDO 实现实时流式查询的坑点
PDO 默认总是缓冲结果,即使你设了 PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false,也得配合 PDO::setAttribute(PDO::ATTR_CURSOR, PDO::CURSOR_UNBUFFERED),而且只能用于 query(),不能用于预处理语句(prepare() + execute() 在 MySQL 驱动下强制缓冲)。
立即学习“PHP免费学习笔记(深入)”;
- 只支持简单
query():带参数就得拼接字符串(注意 SQL 注入!),或改用 MySQLi - 连接必须设好属性:
new PDO($dsn, $u, $p, [PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false]),且之后再调setAttribute() - Apache 的 mod_php 下可能被
output_buffering或zlib.output_compression截断,建议 CLI 或 PHP-FPM + Nginx 并关闭fastcgi_buffering
浏览器端怎么稳定接收逐行数据
直接访问 PHP 脚本地址,多数浏览器会等响应结束才渲染,所以必须用 JS 主动流式读取。推荐 fetch() + response.body.getReader(),比 XMLHttpRequest 更可控。
const resp = await fetch('/stream-query.php');
const reader = resp.body.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) break;
const line = new TextDecoder().decode(value).trim();
if (line) console.log(JSON.parse(line));
}
别依赖 Content-Type: text/event-stream(EventSource),因为 PHP 脚本一旦出错(如 MySQL 断连),整个流就中断,且错误信息不会传给前端 —— 调试时容易卡死找不到原因。
真正的难点不在 PHP 怎么查,而在整条链路(MySQL → PHP → Web Server → Browser)每一环都可能缓存或截断输出。少关一个配置、漏调一次 flush()、或多套了一层反向代理,实时性就没了。











