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的chr和ord函数实现字符加减乘除运算实现代码
Dec 05 PHP
ajax完美实现两个网页 分页功能的实例代码
Apr 16 PHP
php冒泡排序、快速排序、快速查找、二维数组去重实例分享
Apr 24 PHP
PHP下的Oracle客户端扩展(OCI8)安装教程
Sep 10 PHP
php实现获取及设置用户访问页面语言类
Sep 24 PHP
PHP定时任务延缓执行的实现
Oct 08 PHP
PHP 生成N个不重复的随机数
Jan 21 PHP
PHP动态输出JavaScript代码实例
Feb 12 PHP
Smarty模板简单配置与使用方法示例
May 23 PHP
PHP文件及文件夹操作之创建、删除、移动、复制
Jul 13 PHP
PHP链表操作简单示例
Oct 15 PHP
PHP代码重构方法漫谈
Apr 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获取数组中指定的一列实例
2017/12/27 PHP
php基于协程实现异步的方法分析
2019/07/17 PHP
jQuery 第二课 操作包装集元素代码
2010/03/14 Javascript
js控制frameSet示例
2013/09/10 Javascript
Node.js开发指南中的简单实例(mysql版)
2013/09/17 Javascript
JavaScript实现两个Table固定表头根据页面大小自行调整
2014/01/03 Javascript
JS组件系列之Bootstrap Icon图标选择组件
2016/01/28 Javascript
JavaScript设计模式开发中组合模式的使用教程
2016/05/18 Javascript
JS递归遍历对象获得Value值方法技巧
2016/06/14 Javascript
全面了解javascript中的错误处理机制
2016/07/18 Javascript
基于Angularjs+mybatis实现二级评论系统(仿简书)
2017/02/13 Javascript
js 数字、字符串、布尔值的转换方法(必看)
2017/04/07 Javascript
webpack3+React 的配置全解
2017/08/21 Javascript
解决前后端分离 vue+springboot 跨域 session+cookie失效问题
2019/05/13 Javascript
JS实现移动端双指缩放和旋转方法
2019/12/13 Javascript
Ant Design Vue table中列超长显示...并加提示语的实例
2020/10/31 Javascript
[56:29]Secret vs Optic 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
python中split方法用法分析
2015/04/17 Python
Python编程之属性和方法实例详解
2015/05/19 Python
浅谈Python爬取网页的编码处理
2016/11/04 Python
Python实现动态加载模块、类、函数的方法分析
2017/07/18 Python
python设置值及NaN值处理方法
2018/07/03 Python
Django渲染Markdown文章目录的方法示例
2019/01/02 Python
django将数组传递给前台模板的方法
2019/08/06 Python
使用CSS3来代替JS实现交互
2017/08/10 HTML / CSS
军用级手机壳,专为冒险而建:Zizo Wireless
2019/08/07 全球购物
统计员岗位职责
2013/11/14 职场文书
新学期班主任寄语
2014/01/18 职场文书
出纳员岗位职责风险
2014/03/06 职场文书
募捐倡议书
2014/04/14 职场文书
后勤个人工作总结
2015/02/28 职场文书
毕业实习证明范本
2015/06/16 职场文书
小学信息技术教学反思
2016/02/16 职场文书
Python Socket编程详解
2021/04/25 Python
Oracle设置DB、监听和EM开机启动的方法
2021/04/25 Oracle
python pygame 开发五子棋双人对弈
2022/05/02 Python