对比PHP对MySQL的缓冲查询和无缓冲查询


Posted in PHP onJuly 01, 2016

关于缓冲查询和无缓冲查询
MySQL的客户端有两种类型的查询:
缓冲查询:将接收查询的结果并把他们存储在客户端的缓存中,而且接下来获取行记录的请求仅仅从本地内获取。
(1)优点:可以在结果集中自由地移动“当前行”的指针,这样很容易找到,因为结果是存在客户端的。
(2)缺点:需要额外的内存来存储这些结果集,而且需要大量的内存,另外,php中用来运行查询的函数会一直到所有的结果都接收才会返回值。

无缓冲查询:会限制你通过严格的顺序访问查询结果。但他不需要额外的内存来存储整个结果集。你可以在MySQL服务器开始返回值的时候就开始获取而处理或显示数据行。当使用无缓冲结果集时,必须使用mysql_fetch_row函数获取所以的数据行,或者在给服务器发送其他任何命令前用mysql_free_result函数关闭结果集。

哪种类型的查询好?最好的根据是具体情况而定,无缓冲查询在结果集巨大的时为你节省大量的临时内存,而且查询不需要排序时,php在MySQL数据库实际上还在处理时就可以获得第一个数据行。
缓存查询便于寻找,它可以提供一个全面的寻找加速。因为每一个单独的查询的都会快读结束,mysql快速的获取结果集并存放在内存中,而不是在处理PHP代码时保持查询为可用的。
另外一个无缓冲查询的限制是在所有的数据行都被读取或者结果集用mysqli_free_result释放之前,你将无法向服务器发送任何命令。

PHP+MySQL缓冲查询和无缓冲查询
PHP MySQL查询(mysqli,pdo_mysql)默认使用缓冲模式.
也就是说查询结果将一次性从MySQL传输到PHP进程内存中,
这时可以统计结果集的行数,以及移动结果集指针.
缓冲模式下,如果结果集很大,那么PHP进程也会占用大量的内存,
直到结果集被unset或者free.

store_result用于缓冲模式,所有结果一次性存储到PHP进程中:

mysqli::query MYSQLI_STORE_RESULT 
mysqli::store_result 
mysqli_stmt::store_result

如果PHP的MySQL数据库驱动底层用的是libmysqlclient,那么memory_limit不能统计到结果集占用的内存,
除非结果集已经赋值给PHP变量,如果底层使用mysqlnd作为驱动时则可以统计到(PHP从5.4开始底层默认使用mysqlnd).
无缓冲模式下执行的查询将会返回一个resource资源引用,位于MySQL的查询结果等待PHP获取.
无缓冲模式下,PHP进程占用的内存很少,但会增大MySQL服务器的负载.
在PHP取回所有结果前,在当前数据库连接下不能发送其他的查询请求.

use_result表示无缓冲查询:

mysqli::query MYSQLI_USE_RESULT 
mysqli::use_result

总结:
当结果集不大时,或者需要在读取所有行前获取结果集行数时,使用缓冲查询(默认).
当结果集很大时,使用无缓冲查询,避免PHP进程占用大量的内存.

$rs = $mysqli->query("SELECT * FROM City", MYSQLI_USE_RESULT); 
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); 
$rs = $pdo->query("SELECT * FROM City");

默认情况下,mysqli_stmt的SELECT查询结果将留在MySQL服务器上,等待fetch方法把记录逐条取回到PHP程序中,这样做会降低性能,但能节省内存.
如果需要对所有记录进行处理,可以调用mysqli_stmt::store_result,把所有结果一次性全部传回到PHP程序中,
这样做更高效,能减轻MySQL服务器的负担,虽然内存占用会多一些.
如果获取SELECT语句查找到了多少条记录,可以用 mysqli_stmt::$num_rows 获取.
这个属性只有在提前执行过 mysqli_stmt::store_result 方法,将全部查询结果传回到PHP程序中的情况下才可以使用.
对比 mysqli_result::$num_rows 则不没有这个限制.
用 mysqli_stmt::free_result 关闭 mysqli_stmt::store_result:

$stmt->store_result(); 
echo $stmt->num_rows; 
$stmt->free_result();
mysqli_stmt::store_result能让mysqli_stmt::fetch更高效,但也需要用mysqli_stmt::free_result显式关闭. 

可以用mysqli_stmt::get_result拿到结果集对象$result,然后mysqli_result::fetch_all拿到查询数组$results:
$result = $stmt->get_result(); 
$results = $result->fetch_all(MYSQLI_ASSOC);
整理一下相关参数:
mysqli::query//执行SQL,成功返回mysqli_result(SELECT,SHOW,DESCRIBE操作)对象或TRUE(其他操作),失败返回FALSE.用mysqli::close关闭.
mysqli::prepare//预处理SQL,成功返回statement对象,失败返回FALSE.
mysqli_stmt::execute//执行SQL.用mysqli_stmt::close关闭.
mysqli_stmt::store_result//取回全部查询结果(SELECT,SHOW,DESCRIBE,EXPLAIN)到PHP,可选.用mysqli_stmt::free_result关闭.
mysqli_stmt::bind_result//把prepare和execute产生的结构绑定结果到变量,然后在mysqli_stmt::fetch中把这些变量输出或赋值.
mysqli_stmt::fetch//每次返回结果集的一条,赋值给mysqli_stmt::bind_result绑定的变量.
mysqli_stmt::get_result//获得结果对象,然后调用mysqli_result::fetch_all就能返回结果集数组.mysqlnd下可用.
mysqli_result::fetch_all//返回一个结果集数组(MYSQLI_NUM(默认),MYSQLI_ASSOC,MYSQLI_BOTH),用mysqli_result::close关闭.mysqlnd下可用.
mysqli_result::fetch_array//每次返回结果集的一条,包含一个一维的数字数组和关联数组.
mysqli_result::fetch_assoc//每次返回结果集的一条,即一个一维的关联数组.
mysqli_result::fetch_row//每次返回结果集的一条,即一个一维的数字数组.
PHP 相关文章推荐
PHP 获取远程网页内容的代码(fopen,curl已测)
Jun 06 PHP
php中unlink()、mkdir()、rmdir()等方法的使用介绍
Dec 21 PHP
codeigniter集成ucenter1.6双向通信的解决办法
Jun 12 PHP
php解析json数据实例
Aug 19 PHP
php中unserialize返回false的解决方法
Sep 22 PHP
php jsonp单引号转义
Nov 23 PHP
php+xml编程之xpath的应用实例
Jan 24 PHP
php遍历目录方法小结
Mar 10 PHP
Yii2实现log输出到file及database的方法
Nov 12 PHP
PHP实现移除数组中为空或为某值元素的方法
Jan 07 PHP
PHP判断数组是否为空的常用方法(五种方法)
Feb 08 PHP
修改yii2.0用户登录使用的user表为其它的表实现方法(推荐)
Aug 01 PHP
PHP处理CSV表格文件的常用操作方法总结
Jul 01 #PHP
PHP读书笔记整理_结构语句详解
Jul 01 #PHP
PHP安装GeoIP扩展根据IP获取地理位置及计算距离的方法
Jul 01 #PHP
php投票系统之增加与删除投票(管理员篇)
Jul 01 #PHP
PHP读书笔记_运算符详解
Jul 01 #PHP
php+MySql实现登录系统与输出浏览者信息功能
Jul 01 #PHP
php无法连接mysql数据库的正确解决方法
Jul 01 #PHP
You might like
盘点被央视点名过的日本动画电影 一部比一部强
2020/03/08 日漫
PHP高级OOP技术演示
2009/08/27 PHP
php实现判断访问来路是否为搜索引擎机器人的方法
2015/04/15 PHP
thinkphp多表查询两表有重复相同字段的完美解决方法
2016/09/22 PHP
JS去除字符串的空格增强版(可以去除中间的空格)
2009/08/26 Javascript
jquery tab插件制作实现代码
2010/06/22 Javascript
JS交换变量的方法
2015/01/21 Javascript
JavaScript中模拟实现jsonp
2015/06/19 Javascript
JavaScript 七大技巧(一)
2015/12/13 Javascript
Angularjs使用directive自定义指令实现attribute继承的方法详解
2016/08/05 Javascript
socket.io实现在线群聊功能
2017/04/07 Javascript
vue iview组件表格 render函数的使用方法详解
2018/03/15 Javascript
JS中判断字符串存在和非空的方法
2018/09/12 Javascript
Python的Django应用程序解决AJAX跨域访问问题的方法
2016/05/31 Python
简单谈谈python中的多进程
2016/11/06 Python
根据DataFrame某一列的值来选择具体的某一行方法
2018/07/03 Python
Python实现监控键盘鼠标操作示例【基于pyHook与pythoncom模块】
2018/09/04 Python
Python使用pydub库对mp3与wav格式进行互转的方法
2019/01/10 Python
python运行时强制刷新缓冲区的方法
2019/01/14 Python
opencv实现静态手势识别 opencv实现剪刀石头布游戏
2019/01/22 Python
python 实现将文件或文件夹用相对路径打包为 tar.gz 文件的方法
2019/06/10 Python
python实现小世界网络生成
2019/11/21 Python
PyTorch笔记之scatter()函数的使用
2020/02/12 Python
python网络编程socket实现服务端、客户端操作详解
2020/03/24 Python
python实现猜拳游戏项目
2020/11/30 Python
HTML5移动端手机网站开发流程
2016/04/25 HTML / CSS
解决方案设计综合面试题
2015/08/31 面试题
Java面试题:说出如下代码的执行结果
2015/10/30 面试题
优秀驾驶员先进事迹材料
2014/05/04 职场文书
抗震救灾标语
2014/06/26 职场文书
护士工作失误检讨书
2014/09/14 职场文书
构建和谐校园倡议书
2015/01/19 职场文书
2015年招生工作总结
2015/05/04 职场文书
患者身份识别制度
2015/08/06 职场文书
详解Redis瘦身指南
2021/05/26 Redis
python语言中pandas字符串分割str.split()函数
2022/08/05 Python