应优先用 fetch() 处理大数据集、导出或流式响应,因其单行获取、内存占用低;需配合 while 循环,禁用缓冲查询才能真正流式;fetchAll() 易致内存暴涨、键重复、空数组误判;单字段值用 fetchColumn() 最轻量;多结果集须手动 nextRowset()。

直接用 fetch()、fetchAll() 或 fetchColumn(),别先想着“全取出来”,得看你要什么、有多少数据、要不要类型控制。
什么时候该用 fetch() 而不是 fetchAll()
处理大表、导出 CSV、流式响应时,fetch() 是默认选择。它每次只从结果集里拿一行,内存占用低,不会因为几万条记录把 PHP 进程撑爆。
- 必须配合
while循环使用,比如while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { ... } - 如果忘了写循环或提前
break,就只会拿到第一行 - 不建议在
fetch()后再调fetchAll()—— 游标已移动,后面的数据会丢 - 对 MySQL,默认是缓冲查询(buffered),所以即使你只 fetch 一行,整个结果集其实已在内存里;如需真正流式,得显式禁用:
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false)
fetchAll() 的三种常见陷阱
fetchAll() 看似省事,但容易在三个地方翻车:内存、类型、空结果。
- 查 10 万行用户数据时调
fetchAll(),PHP 内存可能瞬间飙到 200MB+,尤其字段含 TEXT/BLOB - 不传参数时默认返回
PDO::FETCH_BOTH,数组里键重复([0] => 'foo', 'name' => 'foo'),调试时容易误判 - 查询无结果时返回空数组
[],不是null或false,直接if ($rows)判空会误认为有数据 - 想让它返回关联数组?明确传
PDO::FETCH_ASSOC,别依赖全局设置 —— 其他代码可能改过PDO::ATTR_DEFAULT_FETCH_MODE
如何安全获取单个字段值(比如统计数、状态码)
别用 fetch() 拿整行再取 $row['count'],更别 fetchAll()[0]['count'] —— 这是典型过度提取。
- 用
fetchColumn(0),参数是列序号(从 0 开始),最轻量 - 它返回的是标量值,查
SELECT COUNT(*)时直接得到 int,不用再解包 - 注意:如果结果集为空,
fetchColumn()返回false,不是null,判断时用=== false更稳妥 - 执行
SELECT id FROM users LIMIT 1后调fetchColumn(),拿到的就是那个id值,没多余结构
多结果集(比如存储过程)必须手动切换游标
SQL Server 或 MySQL 存储过程返回多个 SELECT 时,PDO 不会自动跳到下一个结果集 —— 你得自己调 nextRowset()。
- 第一次
fetch()拿的是第一个SELECT的结果 - 要读第二个结果集,必须先
$stmt->nextRowset(),再fetch()或fetchAll() - 漏掉这步,后续所有获取操作都返回
false,且无报错提示 - 输出参数(
PDO::PARAM_INPUT_OUTPUT)和结果集是并行的,nextRowset()不影响参数值,它们早就在变量里了
最常被忽略的其实是 fetch 模式和空结果行为 —— 它们不报错,但会让逻辑悄悄跑偏。写完记得检查:你真的需要全部数据吗?你拿到的到底是 false 还是空数组?游标是不是卡在第一个结果集不动了?











