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 相关文章推荐
我的论坛源代码(四)
Oct 09 PHP
PHP获取网站域名和地址的代码
Aug 17 PHP
PHP字符串 ==比较运算符的副作用
Oct 21 PHP
PHP在获取指定目录下的目录,在获取的目录下面再创建文件,多平台
Aug 03 PHP
你应该知道PHP浮点数知识
May 13 PHP
Session 失效的原因汇总及解决丢失办法
Sep 30 PHP
PHP文件操作详解
Dec 30 PHP
thinkPHP框架中layer.js的封装与使用方法示例
Jan 18 PHP
Laravel5.7 Eloquent ORM快速入门详解
Apr 12 PHP
ThinkPHP框架结合Ajax实现用户名校验功能示例
Jul 03 PHP
TP5框架model常见操作示例小结【增删改查、聚合、时间戳、软删除等】
Apr 05 PHP
php设计模式之观察者模式实例详解【星际争霸游戏案例】
Mar 30 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用户注册页面利用js进行表单验证具体实例
2013/10/17 PHP
php实现压缩合并js的方法【附demo源码下载】
2016/09/22 PHP
jQuery 获取对象 基本选择与层级
2010/05/31 Javascript
javascrpt绑定事件之匿名函数无法解除绑定问题
2012/12/06 Javascript
使用jQuery实现的网页版的个人简历(可换肤)
2013/04/19 Javascript
JQuery调webservice实现邮箱验证(检测是否可用)
2013/05/21 Javascript
document.documentElement和document.body区别介绍
2013/09/16 Javascript
获取3个数组不重复的值的具体实现
2013/12/30 Javascript
可自定义速度的js图片无缝滚动示例分享
2014/01/20 Javascript
js/jquery判断浏览器的方法小结
2014/09/02 Javascript
JavaScript中document.forms[0]与getElementByName区别
2015/01/21 Javascript
浅谈javascript中的instanceof和typeof
2015/02/27 Javascript
javascript实现支持移动设备画廊
2015/08/24 Javascript
Node.js制作简单聊天室
2017/01/12 Javascript
jQuery简单实现MD5加密的方法
2017/03/03 Javascript
vue-hook-form使用详解
2017/04/07 Javascript
jquery实现图片上传前本地预览
2017/04/28 jQuery
基于代数方程库Algebra.js解二元一次方程功能示例
2017/06/09 Javascript
Node.js利用js-xlsx处理Excel文件的方法详解
2017/07/05 Javascript
基于vue cli重构多页面脚手架过程详解
2018/01/23 Javascript
vue2.0实现移动端的输入框实时检索更新列表功能
2018/05/08 Javascript
微信公众号开发之微信支付代码记录的实现
2019/10/16 Javascript
基于javascript实现日历功能原理及代码实例
2020/05/07 Javascript
vue抽出组件并传值实例
2020/07/31 Javascript
Vue+element-ui添加自定义右键菜单的方法示例
2020/12/08 Vue.js
python 常见的排序算法实现汇总
2020/08/21 Python
python判断变量是否为列表的方法
2020/09/17 Python
玩转CSS3色彩
2010/01/16 HTML / CSS
美国战术品牌:5.11 Tactical
2019/05/01 全球购物
美国健康和保健平台:healtop
2020/07/02 全球购物
.net软件工程师应聘上机试题
2015/03/10 面试题
爱国演讲稿400字
2014/05/07 职场文书
不知如何爱孩子,这些方法教会您
2019/08/06 职场文书
在Django中使用MQTT的方法
2021/05/10 Python
关于python中模块和重载的问题
2021/11/02 Python
一文了解Java动态代理的原理及实现
2022/07/07 Java/Android