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 相关文章推荐
优化使用mysql存储session的php代码
Jan 10 PHP
PHP Mysql编程之高级技巧
Aug 27 PHP
PHP mail 通过Windows的SMTP发送邮件失败的解决方案
May 27 PHP
关于使用coreseek并为其做分页的介绍
Jun 21 PHP
php中文验证码实现示例分享
Jan 12 PHP
Win7 64位系统下PHP连接Oracle数据库
Aug 20 PHP
php判断数组中是否存在指定键(key)的方法
Mar 17 PHP
PHP编写简单的App接口
Aug 28 PHP
一个简单安全的PHP验证码类、PHP验证码
Sep 24 PHP
PHP利用正则表达式将相对路径转成绝对路径的方法示例
Feb 28 PHP
PHP基于迭代实现文件夹复制、删除、查看大小等操作的方法
Aug 11 PHP
laravel excel 上传文件保存到本地服务器功能
Nov 14 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
Laravel中使用自己编写类库的3种方法
2015/02/10 PHP
php判断访问IP的方法
2015/06/19 PHP
PHP模块化安装教程
2016/06/01 PHP
php微信高级接口群发 多客服
2016/06/23 PHP
thinkphp5修改view到根目录实例方法
2019/07/02 PHP
yii2.0框架实现上传excel文件后导入到数据库的方法示例
2020/04/13 PHP
JavaScript判断窗口是否最小化的代码(跨浏览器)
2010/08/01 Javascript
JS JSON对象转为字符串的简单实现方法
2013/11/18 Javascript
jQuery的事件委托实例分析
2015/07/15 Javascript
Backbone View 之间通信的三种方式
2016/08/09 Javascript
浅谈JS继承_借用构造函数 & 组合式继承
2016/08/16 Javascript
jquery弹出框插件jquery.ui.dialog用法分析
2016/08/20 Javascript
微信小程序的日期选择器的实例详解
2017/09/29 Javascript
解决js ajax同步请求造成浏览器假死的问题
2018/01/18 Javascript
JS浅拷贝和深拷贝原理与实现方法分析
2019/02/28 Javascript
微信小程序实现获取小程序码和二维码java接口开发
2019/03/29 Javascript
vue 点击展开显示更多(点击收起部分隐藏)
2019/04/09 Javascript
file-loader打包图片文件时路径错误输出为[object-module]的解决方法
2020/01/03 Javascript
如何通过javaScript去除字符串两端的空白字符
2020/02/06 Javascript
Python(Tornado)模拟登录小米抢手机
2013/11/12 Python
举例讲解Python的Tornado框架实现数据可视化的教程
2015/05/02 Python
Python引用传值概念与用法实例小结
2017/10/07 Python
matplotlib subplots 调整子图间矩的实例
2018/05/25 Python
Python3按一定数据位数格式处理bin文件的方法
2019/01/24 Python
python实现蒙特卡罗方法教程
2019/01/28 Python
对Django外键关系的描述
2019/07/26 Python
浅谈python处理json和redis hash的坑
2020/07/16 Python
如何基于python把文字图片写入word文档
2020/07/31 Python
大学毕业生通用求职信
2013/09/28 职场文书
打架检讨书500字
2014/01/29 职场文书
给老婆的保证书范文
2014/04/28 职场文书
公证委托书标准格式
2014/09/11 职场文书
个人融资协议书
2014/10/02 职场文书
2015年班长个人工作总结
2015/04/03 职场文书
2016年暑期教师培训心得体会
2016/01/09 职场文书
JavaScript正则表达式实现注册信息校验功能
2022/05/30 Java/Android