游标本质是数据库逐行返回结果集的机制,用于解决整结果集加载导致的内存溢出问题;其核心价值在于控制内存占用、分批处理大数据、减轻数据库IO压力。

选对方式比写对代码更关键。游标、生成器、分块处理不是替代关系,而是解决不同瓶颈的工具:游标管数据读取方式,生成器管内存调度,分块处理管任务切分粒度。用错场景,再“高级”的写法也会OOM或变慢。
游标:解决“数据还没开始处理就爆内存”的问题
根本矛盾在于 MySQLi/PDO 默认把整张结果集塞进 PHP 内存。游标是底层机制,让数据库边查边传,PHP 边收边用。
- MySQLi 必须用 MYSQLI_USE_RESULT 模式调用
query(),不能用fetch_all();处理完必须调用$result->free() - PDO 必须在
execute()前设置PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false,否则 yield 写得再漂亮也白搭 - 限制:游标期间不能在同一连接上执行其他查询,否则报 Commands out of sync
生成器:解决“逻辑层内存持续累积”的问题
生成器本身不省内存,它只是把游标读出的每一行,以可控节奏吐给业务层。真正起作用的是它配合游标形成的“单行生命周期”——一行被 yield 出去、被消费、被销毁,内存就立刻释放。
- 不要在生成器函数里做耗时操作(比如发 HTTP 请求、写日志),否则会卡住整个流
- 生成器返回的是
Generator对象,只能遍历一次;需要多次消费,得重新调用生成器函数 - 适合场景:逐行转换、过滤、轻量计算,例如清洗日志字段、格式化导出数据
分块处理:解决“任务不可中断、失败难恢复”的问题
分块不是技术方案,而是工程策略。它用主键/时间戳分页,每次只取固定数量记录(如 1000 条),处理完再取下一批。天然支持断点续传、失败重试、并发控制。
立即学习“PHP免费学习笔记(深入)”;
- 单表直接用主键分页(
WHERE id > ? ORDER BY id LIMIT 1000)最稳定 - 连表场景必须显式指定排序字段和分块依据,否则 ThinkPHP 等框架的
chunk()可能报错或漏数据 - 注意:分块会多次查询数据库,IO 开销上升,但换来的是可控性与稳定性
实际组合推荐:高吞吐导出用「游标 + 生成器」;后台定时任务用「分块处理」;若需边读边写且要容错,可先用游标读入临时表,再用分块更新。



















