根本原因是PHP默认全量缓存查询结果,应禁用缓冲并流式处理:使用PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>false或mysqli::use_result(),配合及时释放资源与循环内unset。

PHP查大表内存溢出,根本原因不是数据太大,而是默认把整张结果集全塞进内存里——改用 mysql_unbuffered_query 或 PDO 的无缓冲模式,才能真正切断内存暴涨链。
为什么 mysql_query 会吃光内存
它执行完 SQL 后,立刻把全部结果从 MySQL 服务端拉到 PHP 进程内存中缓存起来。哪怕你只 while ($row = mysql_fetch_assoc($result)) 逐行取,那几百万行数据早已躺在内存里了。更糟的是,这种缓冲还支持 mysql_num_rows()、mysql_data_seek() 等随机访问操作,代价就是内存翻倍占用。
- 常见错误现象:
Fatal error: Allowed memory size of 134217728 bytes exhausted出现在mysql_query()返回后、甚至还没开始fetch时 - 使用场景:导出全表、日志归档、ETL 抽取等无法加
LIMIT的批量读取 - 注意:
mysql_*函数在 PHP 7.0+ 已被移除,实际应切换至PDO或mysqli对应的无缓冲接口
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false 怎么配才生效
这个选项必须在 PDOStatement 创建前就设定,且仅对当前查询起作用。设成 true(默认)就退回老路;设成 false 才启用流式拉取——MySQL 服务端每发一行,PHP 就处理一行,不囤积。
- 实操写法示例:
$pdo = new PDO($dsn, $user, $pass, [ PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false, PDO::ATTR_EMULATE_PREPARES => false, ]); $stmt = $pdo->query("SELECT * FROM huge_table"); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { // 处理单行,内存基本恒定 } - 容易踩的坑:PDO 预处理语句(
prepare()+execute())下该属性无效,必须用query()直接执行;若用了ATTR_EMULATE_PREPARES => true,也会强制走缓冲模式 - 性能影响:数据库连接会保持更久(直到最后一行取完),并发高时可能撑满 MySQL 的
max_connections
为什么不能用 mysqli::use_result() 替代 store_result()
mysqli_query() 默认调用 store_result(),即缓冲模式;要切流式,得显式调用 mysqli::use_result() 获取结果集,再配合 mysqli_fetch_assoc() 使用。但二者不可混用——同一连接上,一旦调用了 use_result(),就不能再执行其他查询,除非先 mysqli_free_result() 或关闭连接。
- 典型报错:
Commands out of sync; you can't run this command now,就发生在你试图在未释放use_result()结果时又发新查询 - 正确顺序:
$result = $mysqli->use_result(); while ($row = $result->fetch_assoc()) { ... } $result->free(); - 参数差异:
use_result()不支持num_rows、data_seek、fetch_all等依赖完整结果集的方法,一调就返回false或警告
流式查询后内存还是涨?检查这三处泄漏点
即使开了无缓冲,内存仍缓慢上涨,大概率不是查询本身的问题,而是后续处理环节在悄悄囤积数据。
- 别在循环里拼大字符串:
$log .= $row['msg']比$lines[] = $row['msg'];+implode()更易触发重复分配 - 别反复
json_decode($huge_json, true):设false返回对象,省内存约 15%,尤其字段名重复多时 - 别漏掉
$stmt->closeCursor()(PDO)或$result->free()(MySQLi):不显式释放,结果集资源可能滞留在扩展层,memory_get_usage(true)看不到,但进程 RSS 持续上升
真正的瓶颈往往不在 SQL 执行那一瞬,而在你把流式吐出的每一行,又塞进了哪个没清理的数组、对象或静态缓存里。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











