最近在研究PHP,很喜欢,碰到PHP并发查询MySQL的问题,研究了一下,顺便留个笔记:

同步查询
这是我们最常的调用模式,客户端调用Query[函数],发起查询命令,等待结果返回,读取结果;再发送第二条查询命令,等待结果返回,读取结果。总耗时,会是两次查询的时间之和。简化一下过程,例如下图:
例图,由1.1到1.3为一个Query[函数]的调用,两次查询,就要串行经历1.1、1.2、1.3、2.1、2.2、2.3,尤其在1.2和2.2会阻塞等待,进程没法做其他事情。
同步调用的好处是,符合我们的直观思维,调用和处理都简单。缺点是进程阻塞在等待结果返回,增加额外的运行时间。
如果,有多条查询请求,或者进程还有其他的事情处理,那么能否把等待的时间也合理利用起来,提高进程的处理能力呢,显然是可以的。
拆分
现在,我们把Query[函数]打碎,客户端在1.1后,马上返回,客户端跳过1.2,在1.3有数据达到后再去读取数据。这样进程在原来的1.2阶段就解放了,可以做更多的事情,例如…再发起一条sql查询[2.1],是否看到了并发查询的雏形了。
并发查询
相对于同步查询的下一条查询的发起都在上一条完成后,并发查询,可以在上一条查询请求发起后,立刻发起下一条查询请求。简化一下过程,下图:
例图,在1.1.1成功发送完请求后,立马返回[1.1.2],最终查询结果的返回时在遥远的1.2 。但是在,1.1.1到1.2中间,还发起了另一个查询请求,这时间段内,就同时发起了两条查询请求,2.2先于1.2到达,那么两条查询的总耗时,只相当于第一条查询的时间。
并发查询的优点是,可以提高进程的使用率,避免阻塞等待服务器处理查询,缩短了多条查询的耗时。但缺点也很明显,发起N条并发查询,就需要建立N条数据库链接,对于有数据库连接池的应用来说,可以避免这种情况。
退化
理想情况下,我们希望并发N条查询,总耗时等于查询时间最长的一条查询。但也有可能并发查询会[退化]为[同步查询]。What?例图中,如果1.2在2.1.1前就返回了,那么并发查询就[退化]为[同步查询]了,但付出的代价却比同步查询要高。
多路复用
那么,怎么等待知道什么时候查询结果返回了,又是哪个的查询结果返回呢?
对每个查询IO调用read?如果是遇上阻塞IO,这样就会阻塞在一个IO上,其他IO有结果返回了,也没法处理。那么,如果是非阻塞IO,那不用怕会阻塞在其中一个IO上了,确实是,但又会造成不断地轮询判断,浪费CPU资源。
对于这种情况可以使用多路复用轮询多个IO。
PHP实现并发查询MySQL
PHP的mysqli(mysqlnd驱动)提供多路复用轮询IO(mysqli_poll)和异步查询(MYSQLI_ASYNC、mysqli_reap_async_query),使用这两个特性实现并发查询,示例代码:
<?php
$sqls = array(
'SELECT * FROM `mz_table_1` LIMIT 1000,10',
'SELECT * FROM `mz_table_1` LIMIT 1010,10',
'SELECT * FROM `mz_table_1` LIMIT 1020,10',
'SELECT * FROM `mz_table_1` LIMIT 10000,10',
'SELECT * FROM `mz_table_2` LIMIT 1',
'SELECT * FROM `mz_table_2` LIMIT 5,1'
);
$links = [];
$tvs = microtime();
$tv = explode(' ', $tvs);
$start = $tv[1] * 1000 + (int)($tv[0] * 1000);
// 链接数据库,并发起异步查询
foreach ($sqls as $sql) {
$link = mysqli_connect('127.0.0.1', 'root', 'root', 'dbname', '3306');
$link->query($sql, MYSQLI_ASYNC); // 发起异步查询,立即返回
$links[$link->thread_id] = $link;
}
$llen = count($links);
$process = 0;
do {
$r_array = $e_array = $reject = $links;
// 多路复用轮询IO
if(!($ret = mysqli_poll($r_array, $e_array, $reject, 2))) {
continue;
}
// 读取有结果返回的查询,处理结果
foreach ($r_array as $link) {
if ($result = $link->reap_async_query()) {
print_r($result->fetch_row());
if (is_object($result))
mysqli_free_result($result);
} else {
}
// 操作完后,把当前数据链接从待轮询集合中删除
unset($links[$link->thread_id]);
$link->close();
$process++;
}
foreach ($e_array as $link) {
die;
}
foreach ($reject as $link) {
die;
}
}while($process < $llen);
$tvs = microtime();
$tv = explode(' ', $tvs);
$end = $tv[1] * 1000 + (int)($tv[0] * 1000);
echo $end - $start,PHP_EOL;
mysqli_poll源码:
#ifndef PHP_WIN32
#define php_select(m, r, w, e, t) select(m, r, w, e, t)
#else
#include "win32/select.h"
#endif
/* {{{ mysqlnd_poll */
PHPAPI enum_func_status
mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, int * desc_num)
{
struct timeval tv;
struct timeval *tv_p = NULL;
fd_set rfds, wfds, efds;
php_socket_t max_fd = 0;
int retval, sets = 0;
int set_count, max_set_count = 0;
DBG_ENTER("_mysqlnd_poll");
if (sec < 0 || usec < 0) {
php_error_docref(NULL, E_WARNING, "Negative values passed for sec and/or usec");
DBG_RETURN(FAIL);
}
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&efds);
// 从所有mysqli链接中获取socket链接描述符
if (r_array != NULL) {
*dont_poll = mysqlnd_stream_array_check_for_readiness(r_array);
set_count = mysqlnd_stream_array_to_fd_set(r_array, &rfds, &max_fd);
if (set_count > max_set_count) {
max_set_count = set_count;
}
sets += set_count;
}
// 从所有mysqli链接中获取socket链接描述符
if (e_array != NULL) {
set_count = mysqlnd_stream_array_to_fd_set(e_array, &efds, &max_fd);
if (set_count > max_set_count) {
max_set_count = set_count;
}
sets += set_count;
}
if (!sets) {
php_error_docref(NULL, E_WARNING, *dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
DBG_ERR_FMT(*dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
DBG_RETURN(FAIL);
}
PHP_SAFE_MAX_FD(max_fd, max_set_count);
// select轮询阻塞时间
if (usec > 999999) {
tv.tv_sec = sec + (usec / 1000000);
tv.tv_usec = usec % 1000000;
} else {
tv.tv_sec = sec;
tv.tv_usec = usec;
}
tv_p = &tv;
// 轮询,等待多个IO可读,php_select是select的宏定义
retval = php_select(max_fd + 1, &rfds, &wfds, &efds, tv_p);
if (retval == -1) {
php_error_docref(NULL, E_WARNING, "unable to select [%d]: %s (max_fd=%d)",
errno, strerror(errno), max_fd);
DBG_RETURN(FAIL);
}
if (r_array != NULL) {
mysqlnd_stream_array_from_fd_set(r_array, &rfds);
}
if (e_array != NULL) {
mysqlnd_stream_array_from_fd_set(e_array, &efds);
}
// 返回可操作的IO数量
*desc_num = retval;
DBG_RETURN(PASS);
}
并发查询操作结果
为了更直观地看效果,我找了一个1.3亿数据量并且没有优化过的表进行操作。
并发查询的结果:
同步查询的结果:
从结果来看,同步查询的总耗时是所有查询的时间的累加;而并发查询的总耗时在这里其实是查询时间最长的那一条(同步查询的第四条,耗时是10几秒,符合并发查询的总耗时),而且并发查询的查询顺序和结果到达的顺序是不一样的。
多条耗时较短的查询对比
使用多条查询时间较短的sql进行对比一下
并发查询的测试1结果(数据库链接时间也统计进去):
同步查询的结果(数据库链接时间也统计进去):
并发查询的测试2结果(不统计数据库链接时间):
从结果上看,并发查询测试1并没有讨到好处。从同步查询上看,每条查询耗时大概3-4ms左右。但如果不把数据库链接时间统计进去(同步查询只有一次数据库链接),并发查询的优势又能体现出来了。
结语
这里探讨了一下PHP实现并发查询MySQL,从实验上结果直观地认识了并发查询的优缺点。建立数据库连接的时间在一条优化了的sql查询上,占得比重还是很大。#没有连接池,要你何用
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# PHP并发查询MySQL
# PHP
# 并发查询
# php并发对MYSQL造成压力的解决方法
# 解析php mysql 事务处理回滚操作(附实例)
# php实现mysql事务处理的方法
# php下pdo的mysql事务处理用法实例
# PHP+Mysql基于事务处理实现转账功能的方法
# php+Mysqli利用事务处理转账问题实例
# PHP通过插入mysql数据来实现多机互锁实例
# PHP+MySQL高并发加锁事务处理问题解决方法
# 多条
# 多路
# 复用
# 查询结果
# 多个
# 两次
# 客户端
# 这种情况
# 两条
# 上看
# 再发
# 较短
# 时间最长
# 这是
# 就会
# 连接池
# 在这里
# 都在
# 又是
# 有可能
相关文章:
实例解析angularjs的filter过滤器
,石家庄四十八中学官网?
西安制作网站公司有哪些,西安货运司机用的最多的app或者网站是什么?
制作销售网站教学视频,销售网站有哪些?
潍坊网站制作公司有哪些,潍坊哪家招聘网站好?
如何在搬瓦工VPS快速搭建网站?
子杰智能建站系统|零代码开发与AI生成SEO优化指南
微信网站制作公司有哪些,民生银行办理公司开户怎么在微信网页上查询进度?
清除minerd进程的简单方法
C++如何将C风格字符串(char*)转换为std::string?(代码示例)
如何基于PHP生成高效IDC网络公司建站源码?
建站之星如何快速生成多端适配网站?
湖州网站制作公司有哪些,浙江中蓝新能源公司官网?
,制作一个手机app网站要多少钱?
如何制作网站标识牌,动态网站如何制作(教程)?
怀化网站制作公司,怀化新生儿上户网上办理流程?
阿里云网站制作公司,阿里云快速搭建网站好用吗?
天河区网站制作公司,广州天河区如何办理身份证?需要什么资料有预约的网站吗?
建站为何优先选择香港服务器?
如何获取免费开源的自助建站系统源码?
广东企业建站网站优化与SEO营销核心策略指南
微网站制作教程,我微信里的网站怎么才能复制到浏览器里?
如何解决ASP生成WAP建站中文乱码问题?
网站制作公司排行榜,抖音怎样做个人官方网站
制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?
电影网站制作价格表,那些提供免费电影的网站,他们是怎么盈利的?
如何在IIS服务器上快速部署高效网站?
建站org新手必看:2024最新搭建流程与模板选择技巧
深圳企业网站制作设计,在深圳如何网上全流程注册公司?
如何快速搭建高效可靠的建站解决方案?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
Python如何创建带属性的XML节点
山东网站制作公司有哪些,山东大源集团官网?
如何配置支付宝与微信支付功能?
如何获取上海专业网站定制建站电话?
制作国外网站的软件,国外有哪些比较优质的网站推荐?
视频网站app制作软件,有什么好的视频聊天网站或者软件?
南阳网站制作公司推荐,小学电子版试卷去哪里找资源好?
如何快速生成可下载的建站源码工具?
如何挑选高效建站主机与优质域名?
如何通过多用户协作模板快速搭建高效企业网站?
上海制作企业网站有哪些,上海有哪些网站可以让企业免费发布招聘信息?
保定网站制作方案定制,保定招聘的渠道有哪些?找工作的人一般都去哪里看招聘信息?
建站之星好吗?新手能否轻松上手建站?
如何通过山东自助建站平台快速注册域名?
电商网站制作公司有哪些,1688网是什么意思?
网站专业制作公司有哪些,做一个公司网站要多少钱?
建站主机服务器选购指南:轻量应用与VPS配置解析
定制建站策划方案_专业建站与网站建设方案一站式指南
香港服务器租用费用高吗?如何避免常见误区?
*请认真填写需求信息,我们会在24小时内与您取得联系。