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 htmlspecialchars加强版
Feb 16 PHP
PHP操作MongoDB时的整数问题及对策说明
May 02 PHP
php 无法加载mcrypt.dll的解决办法
Apr 03 PHP
ThinkPHP之foreach标签使用概述
Jun 30 PHP
修复ShopNC使用QQ 互联时提示100010 错误
Nov 08 PHP
WordPress开发中自定义菜单的相关PHP函数使用简介
Jan 05 PHP
浅谈PHP拦截器之__set()与__get()的理解与使用方法
Oct 18 PHP
修改yii2.0用户登录使用的user表为其它的表实现方法(推荐)
Aug 01 PHP
php curl获取到json对象并转成数组array的方法
May 31 PHP
thinkPHP框架实现生成条形码的方法示例
Jun 06 PHP
Thinkphp自定义生成缩略图尺寸的方法
Aug 05 PHP
PHP设计模式之装饰器(装饰者)模式(Decorator)入门与应用详解
Dec 13 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/11/19 PHP
PHP文件注释标记及规范小结
2012/04/01 PHP
php利用腾讯ip分享计划获取地理位置示例分享
2014/01/20 PHP
php使用Header函数,PHP_AUTH_PW和PHP_AUTH_USER做用户验证
2016/05/04 PHP
php 伪造HTTP_REFERER页面URL来源的三种方法
2016/09/22 PHP
php简单压缩css样式示例
2016/09/22 PHP
php获取给定日期相差天数的方法分析
2017/02/20 PHP
浏览器脚本兼容 文本框中,回车键触发事件的兼容
2010/06/21 Javascript
js 中 document.createEvent的用法
2010/08/29 Javascript
js中匿名函数的N种写法
2010/09/08 Javascript
基于MVC3方式实现下拉列表联动(JQuery)
2013/09/02 Javascript
js 限制input只能输入数字、字母和汉字等等
2013/12/18 Javascript
jQuery select表单提交省市区城市三级联动核心代码
2014/06/09 Javascript
javascript实现手机震动API代码
2015/08/05 Javascript
AngularJS中的Directive自定义一个表格
2016/01/25 Javascript
AngularJS 依赖注入详解和简单实例
2016/07/28 Javascript
BootStrap入门教程(一)之可视化布局
2016/09/19 Javascript
jQuery中可见性过滤器简单用法示例
2018/03/31 jQuery
vue-cli项目中使用公用的提示弹层tips或加载loading组件实例详解
2018/05/28 Javascript
详解基于 Node.js 的轻量级云函数功能实现
2019/07/08 Javascript
Node.js API详解之 net模块实例分析
2020/05/18 Javascript
[01:02:34]TFT vs VGJ.T Supermajor 败者组 BO3 第二场 6.5
2018/06/06 DOTA
Python Tkinter简单布局实例教程
2014/09/03 Python
python 获取文件下所有文件或目录os.walk()的实例
2018/04/23 Python
Python自动抢红包教程详解
2019/06/11 Python
Python 通过微信控制实现app定位发送到个人服务器再转发微信服务器接收位置信息
2019/08/05 Python
最新版 Windows10上安装Python 3.8.5的步骤详解
2020/11/28 Python
Crocs欧洲官网:Crocs Europe
2020/01/14 全球购物
计算机本科生自荐信
2013/10/15 职场文书
网吧消防安全制度
2014/01/28 职场文书
夫妻分居协议书范文
2014/11/26 职场文书
2015年个人招商工作总结
2015/04/25 职场文书
清明节随笔
2015/08/15 职场文书
2016年党员公开承诺书范文
2016/03/24 职场文书
Python 用户输入和while循环的操作
2021/05/23 Python
uniapp开发打包多端应用完整方法指南
2022/12/24 Javascript