PHP查询MySQL大量数据的时候内存占用分析


Posted in PHP onJuly 22, 2011

昨天, 有同事在PHP讨论群里提到, 他做的一个项目由于MySQL查询返回的结果太多(达10万条), 从而导致PHP内存不够用. 所以, 他问, 在执行下面的代码遍历返回的MySQL结果之前, 数据是否已经在内存中了? -

while ($row = mysql_fetch_assoc($result)) { 

// ... 

}

当然, 这种问题有许多优化的方法. 不过, 就这个问题来讲, 我首先想到, MySQL是经典的C/S(Client/Server, 客户端/服务器)模型, 在遍历结果集之前, 底层的实现可能已经把所有的数据通过网络(假设使用TCP/IP)读到了Client的缓冲区, 也有另一种可能, 就是数据还在Server端的发送缓冲区里, 并没有传给Client.

在查看PHP和MySQL的源码之前, 我注意到PHP手册里有两个功能相近的函数:

mysql_query() 

mysql_unbuffered_query()

两个函数的字面意思和说明证实了我的想法, 前一个函数执行时, 会把所有的结果集从Server端读到Client端的缓冲区中, 而后一个则没有, 这就是”unbuffered(未缓冲)”的意思.

那就是说, 如果用mysql_unbuffered_query()执行了一条返回大量结果集的SQL语句, 在遍历结果之前, PHP的内存是没有被结果集占用的. 而用mysql_query()来执行同样的语句的话, 函数返回时, PHP的内存占用便会急剧增加, 立即耗光内存.

如果阅读PHP的相关代码, 可以看到这两个函数的实现上的异同:

/* {{{ proto resource mysql_query(string query [, int link_identifier]) 

Sends an SQL query to MySQL */ 

PHP_FUNCTION(mysql_query) 

{ 

php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_STORE_RESULT); 

} 

/* }}} */ 

/* {{{ proto resource mysql_unbuffered_query(string query [, int link_identifier]) 

Sends an SQL query to MySQL, without fetching and buffering the result rows */ 

PHP_FUNCTION(mysql_unbuffered_query) 

{ 

php_mysql_do_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQL_USE_RESULT); 

} 

/* }}} */

两个函数都调用了php_mysql_do_query(), 只差了第2个参数的不同, MYSQL_STORE_RESULT和MYSQL_USE_RESULT. 再看php_mysql_do_query()的实现:

if(use_store == MYSQL_USE_RESULT) { 

mysql_result=mysql_use_result(&mysql->conn); 

} else { 

mysql_result=mysql_store_result(&mysql->conn); 

}

mysql_use_result()和mysql_store_result()是MySQL的C API函数, 这两个C API函数的区别就是后者把结果集从MySQL Server端全部读取到了Client端, 前者只是读取了结果集的元信息.

回到PHP, 使用mysql_unbuffered_query(), 可以避免内存的立即占用. 如果在遍历的过程不对结果进行”PHP缓存”(如放到某数组中), 则整个执行过程虽然操作了十万条或者百万条或者更多的数据, 但PHP占用的内存始终是非常小的.

PHP 相关文章推荐
php一些公用函数的集合
Mar 27 PHP
解析PHP将对象转换成数组的方法(兼容多维数组类型)
Jun 21 PHP
PHP解析html类库simple_html_dom的转码bug
May 22 PHP
php采用curl访问域名返回405 method not allowed提示的解决方法
Jun 26 PHP
yii操作session实例简介
Jul 31 PHP
PHP中创建图像并绘制文字的例子
Nov 19 PHP
smarty自定义函数用法示例
May 20 PHP
PHP  实现等比压缩图片尺寸和大小实例代码
Oct 08 PHP
PHP中常用的魔术方法
Apr 28 PHP
针对thinkPHP5框架存储过程bug重写的存储过程扩展类完整实例
Jun 16 PHP
PHP中有关长整数的一些操作教程
Sep 11 PHP
PHP正则之正向预查与反向预查讲解与实例
Apr 06 PHP
PHP性能优化 产生高度优化代码
Jul 22 #PHP
PHP多个版本的分析解释
Jul 21 #PHP
QQ登录 PHP OAuth示例代码
Jul 20 #PHP
模板引擎正则表达式调试小技巧
Jul 20 #PHP
php中批量替换文件名的实现代码
Jul 20 #PHP
关于php连接mssql:pdo odbc sql server
Jul 20 #PHP
PHP mcrypt可逆加密算法分析
Jul 19 #PHP
You might like
php面向对象全攻略 (八)重载新的方法
2009/09/30 PHP
PHP 第二节 数据类型之转换
2012/04/28 PHP
解析MySql与Java的时间类型
2013/06/22 PHP
php实现检查文章是否被百度收录
2015/01/27 PHP
PHP Trait代码复用类与多继承实现方法详解
2019/06/17 PHP
JAVASCRIPT style 中visibility和display之间的区别
2010/01/22 Javascript
基于JQuery的数字改变的动画效果--可用来做计数器
2010/08/11 Javascript
JS继承 笔记
2011/07/13 Javascript
JavaScript回调(callback)函数概念自我理解及示例
2013/07/04 Javascript
浅谈Javascript如何实现匀速运动
2014/12/19 Javascript
举例讲解JavaScript中将数组元素转换为字符串的方法
2015/10/25 Javascript
JavaScript实现简易的天数计算器实例【附demo源码下载】
2017/01/18 Javascript
JavaScript中的遍历详解(多种遍历)
2017/04/07 Javascript
Javascript ES6中对象类型Sets的介绍与使用详解
2017/07/17 Javascript
ES6扩展运算符的用途实例详解
2017/08/20 Javascript
vue一个页面实现音乐播放器的示例
2018/02/06 Javascript
JS实现对json对象排序并删除id相同项功能示例
2018/04/18 Javascript
基于Vue实现拖拽功能
2020/07/29 Javascript
angular 用Observable实现异步调用的方法
2018/12/27 Javascript
vue slot与传参实例代码讲解
2019/04/28 Javascript
Vue——前端生成二维码的示例
2020/12/19 Vue.js
[01:23:35]Ti4主赛事胜者组 DK vs EG 1
2014/07/19 DOTA
[01:14]2019完美世界城市挑战赛(秋季赛)全国总决赛精彩花絮
2020/01/08 DOTA
Python中Continue语句的用法的举例详解
2015/05/14 Python
Python 40行代码实现人脸识别功能
2017/04/02 Python
django_orm查询性能优化方法
2018/08/20 Python
CentOS 7下安装Python3.6 及遇到的问题小结
2018/11/08 Python
Python turtle绘画象棋棋盘
2019/08/21 Python
python+opencv实现移动侦测(帧差法)
2020/03/20 Python
EntityManager都有哪些方法
2013/11/01 面试题
90后毕业生的求职信范文
2013/09/21 职场文书
美化环境标语
2014/06/20 职场文书
出差报告范文
2014/11/06 职场文书
《敬重卑微》读后感3篇
2019/11/26 职场文书
图解排序算法之希尔排序Java实现
2021/06/26 Java/Android
解决springboot druid数据库连接失败后一直重连的方法
2022/04/19 Java/Android