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之PHP语法学习笔记1
Dec 17 PHP
PHP实现多服务器session共享之NFS共享的方法
Mar 16 PHP
php+mysql开源XNA 聚合程序发布 下载
Jul 13 PHP
PHP实现的交通银行网银在线支付接口ECSHOP插件和使用例子
May 10 PHP
php生成随机密码自定义函数代码(简单快速)
May 10 PHP
php类的定义与继承用法实例
Jul 07 PHP
php商品对比功能代码分享
Sep 24 PHP
php生成唯一数字id的方法汇总
Nov 18 PHP
php数组分页实现方法
Apr 30 PHP
使用Yii2实现主从数据库设置
Nov 20 PHP
ThinkPHP+EasyUI之ComboTree中的会计科目树形菜单实现方法
Jun 09 PHP
PHP+Ajax实现的无刷新分页功能详解【附demo源码下载】
Jul 03 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实现refresh刷新页面批量导入数据的方法
2014/12/23 PHP
javascript SocialHistory 检查访问者是否访问过某站点
2008/08/02 Javascript
jQuery toggle()设置CSS样式
2009/11/05 Javascript
javascript之学会吝啬 精简代码
2010/04/25 Javascript
JS小功能(列表页面隔行变色)简单实现
2013/11/28 Javascript
JS实现div居中示例
2014/04/17 Javascript
jQuery扁平化风格下拉框美化插件FancySelect使用指南
2015/02/10 Javascript
JS中的THIS和WINDOW.EVENT.SRCELEMENT详解
2015/05/25 Javascript
javascript字符串对象常用api函数小结(连接,替换,分割,转换等)
2016/09/20 Javascript
使用原生的javascript来实现轮播图
2017/02/24 Javascript
mui上拉加载功能实例详解
2017/04/13 Javascript
Javascript实现的StopWatch功能示例
2017/06/13 Javascript
Node.js中sequelize时区的配置方法
2017/12/10 Javascript
学习Vue组件实例
2018/04/28 Javascript
原生JS实现随机点名项目的实例代码
2019/04/30 Javascript
有趣的JavaScript隐式类型转换操作实例分析
2020/05/02 Javascript
基于VSCode调试网页JavaScript代码过程详解
2020/07/20 Javascript
[36:41]完美世界DOTA2联赛循环赛FTD vs Magma第一场 10月30日
2020/10/31 DOTA
理解python多线程(python多线程简明教程)
2014/06/09 Python
在django中使用自定义标签实现分页功能
2017/07/04 Python
配置 Pycharm 默认 Test runner 的图文教程
2018/11/30 Python
Python generator生成器和yield表达式详解
2019/08/08 Python
使用python实现数组、链表、队列、栈的方法
2019/12/20 Python
Python-openpyxl表格读取写入的案例详解
2020/11/02 Python
美国最流行的男士时尚网站:Touch of Modern
2018/02/05 全球购物
澳大利亚波西米亚风情网上商店:Czarina
2019/03/18 全球购物
澳大利亚领先的男装零售连锁店:Lowes
2020/08/07 全球购物
介绍一下HTTP、HTTPS和SSL
2012/12/16 面试题
Linux内核的同步机制是什么?主要有哪几种内核锁
2016/07/11 面试题
自我鉴定范文200字
2013/10/02 职场文书
企业挂职心得体会
2014/09/10 职场文书
四风查摆剖析材料
2014/10/10 职场文书
2015年光棍节活动总结
2015/03/24 职场文书
2015年高中班主任工作总结
2015/04/30 职场文书
导游词之茶卡盐湖
2019/11/26 职场文书
python实现A*寻路算法
2021/06/13 Python