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 压缩文件夹的类代码
Nov 05 PHP
PHP程序员最常犯的11个MySQL错误小结
Nov 20 PHP
php模拟asp中的XmlHttpRequest实现http请求的代码
Mar 24 PHP
PHP5中虚函数的实现方法分享
Apr 20 PHP
基于php的微信公众平台开发入门实例
Apr 15 PHP
php中关于socket的系列函数总结
May 18 PHP
Yii2框架引用bootstrap中日期插件yii2-date-picker的方法
Jan 09 PHP
PHP消息队列用法实例分析
Feb 12 PHP
Zend Framework教程之路由功能Zend_Controller_Router详解
Mar 07 PHP
解决PHP程序运行时:Fatal error: Maximum execution time of 30 seconds exceeded in的错误提示
Nov 25 PHP
CodeIgniter框架钩子机制实现方法【hooks类】
Aug 21 PHP
phpStorm2020 注册码
Sep 17 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模块memcache和memcached区别分析
2011/06/14 PHP
php封装的mongodb操作类代码
2017/08/06 PHP
js整数字符串转换为金额类型数据(示例代码)
2013/12/26 Javascript
js几秒以后倒计时跳转示例
2013/12/26 Javascript
Jquery对数组的操作技巧整理
2014/03/25 Javascript
javascript中数组array及string的方法总结
2014/11/28 Javascript
有效提高JavaScript执行效率的几点知识
2015/01/31 Javascript
Node.js和MongoDB实现简单日志分析系统
2015/04/25 Javascript
jQuery实现textarea自动增长宽高的方法
2015/12/18 Javascript
Jquery EasyUI实现treegrid上显示checkbox并取选定值的方法
2016/04/29 Javascript
ReactNative页面跳转实例代码
2016/09/27 Javascript
详解Vue.js——60分钟组件快速入门(上篇)
2016/12/05 Javascript
js鼠标移动时禁止选中文字
2017/02/19 Javascript
重置Redux的状态数据的方法实现
2019/11/18 Javascript
elementui实现预览图片组件二次封装
2020/12/29 Javascript
js实现简单商品筛选功能
2021/02/02 Javascript
[02:53]DOTA2英雄昆卡基础教程
2013/11/25 DOTA
[01:16:28]DOTA2-DPC中国联赛 正赛 iG vs Magma BO3 第二场 2月23日
2021/03/11 DOTA
在Python程序和Flask框架中使用SQLAlchemy的教程
2016/06/06 Python
python中numpy的矩阵、多维数组的用法
2018/02/05 Python
Flask框架响应、调度方法和蓝图操作实例分析
2018/07/24 Python
python将一组数分成每3个一组的实例
2018/11/14 Python
Python for循环与range函数的使用详解
2019/03/23 Python
python把转列表为集合的方法
2019/06/28 Python
Pytorch修改ResNet模型全连接层进行直接训练实例
2019/09/10 Python
Python实现代码统计工具
2019/09/19 Python
python爬虫 Pyppeteer使用方法解析
2019/09/28 Python
python如何通过twisted搭建socket服务
2020/02/03 Python
历史学专业毕业生求职信
2013/09/27 职场文书
质检部岗位职责
2013/11/11 职场文书
求职信模板
2014/05/23 职场文书
2014年高一班主任工作总结
2014/12/05 职场文书
小学运动会加油稿
2015/07/22 职场文书
Nginx + consul + upsync 完成动态负载均衡的方法详解
2021/03/31 Servers
OpenCV-Python实现图像平滑处理操作
2021/06/08 Python
MySQL 数据库 增删查改、克隆、外键 等操作
2022/05/11 MySQL