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 03 PHP
php递归实现无限分类生成下拉列表的函数
Aug 08 PHP
探讨:parse url解析URL,返回其组成部分
Jun 14 PHP
PHP产生不重复随机数的5个方法总结
Nov 12 PHP
php实现TCP端口检测的方法
Apr 01 PHP
php计算税后工资的方法
Jul 28 PHP
FleaPHP框架数据库查询条件($conditions)写法总结
Mar 19 PHP
PHP yii实现model添加默认值的方法(两种方法)
Nov 10 PHP
Laravel 中使用 Vue.js 实现基于 Ajax 的表单提交错误验证操作
Jun 30 PHP
PHP实现一个多功能购物网站的案例
Sep 13 PHP
ThinkPHP框架获取最后一次执行SQL语句及变量调试简单操作示例
Jun 13 PHP
PHP实现腾讯短网址生成api接口实例
Dec 08 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 缓冲的免费实现方法
2006/10/09 PHP
安装ImageMagick出现error while loading shared libraries的解决方法
2014/09/23 PHP
自制PHP框架之模型与数据库
2017/05/07 PHP
Yii1.1框架实现PHP极光推送消息通知功能
2018/09/06 PHP
神奇的7个jQuery 3D插件整理
2011/01/06 Javascript
Jquery 数据选择插件Pickerbox使用介绍
2012/08/24 Javascript
js实现绿白相间竖向网页百叶窗动画切换效果
2015/03/02 Javascript
jQuery Mobile弹出窗、弹出层知识汇总
2016/01/05 Javascript
JQuery Mobile实现导航栏和页脚
2016/03/09 Javascript
vue cli3.0 引入eslint 结合vscode使用
2019/05/27 Javascript
微信小程序实现拍照画布指定区域生成图片
2019/07/18 Javascript
Vue图片浏览组件v-viewer用法分析【支持旋转、缩放、翻转等操作】
2019/11/04 Javascript
js实现时钟定时器
2020/03/26 Javascript
Javascript实现贪吃蛇小游戏(含详细注释)
2020/10/23 Javascript
原生JavaScript实现贪吃蛇游戏
2020/11/04 Javascript
Python字符串匹配算法KMP实例
2015/07/18 Python
python中的随机函数小结
2018/01/27 Python
Python中fnmatch模块的使用详情
2018/11/30 Python
解决在Python编辑器pycharm中程序run正常debug错误的问题
2019/01/17 Python
python 实现提取某个索引中某个时间段的数据方法
2019/02/01 Python
selenium 安装与chromedriver安装的方法步骤
2019/06/12 Python
Python list与NumPy array 区分详解
2019/11/06 Python
了解一下python内建模块collections
2020/09/07 Python
PyCharm设置注释字体颜色以及是否倾斜的操作
2020/09/16 Python
Ubuntu20下的Django安装的方法步骤
2021/01/24 Python
美体小铺英国官网:The Body Shop英国
2017/01/24 全球购物
俄罗斯Sportmarket体育在线商店:用于旅游和户外活动
2019/11/12 全球购物
关于.NET, HTML的五个问题
2012/08/29 面试题
小学运动会班级口号
2014/06/09 职场文书
旅游饭店管理专业自荐书
2014/06/28 职场文书
群教班子对照检查材料
2014/08/26 职场文书
2014年人力资源部工作总结
2014/11/19 职场文书
个人汇报材料范文
2014/12/30 职场文书
实习护士自荐信
2015/03/25 职场文书
2015年敬老月活动总结
2015/03/27 职场文书
Redis实现分布式锁的五种方法详解
2022/06/14 Redis