宝哥软件园

PHP并发查询MySQL实例代码

编辑:宝哥软件园 来源:互联网 时间:2021-09-04

最近在学习PHP,很喜欢。遇到了PHP中MySQL并发查询的问题,研究了一段时间。对了,我留了张纸条:

同步查询

这是我们最常见的呼叫模式。客户端调用Query[函数],启动查询命令,等待结果返回,并读取结果。然后发送第二个查询命令,等待结果返回,并读取结果。总时间消耗将是两次查询时间的总和。简化流程,如下图:

在图中,从1.1到1.3,调用了一个查询[函数]。两次查询后会依次经过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.2]在1.1.1中成功发送请求后立即返回,最终的查询结果在远处的1.2中返回。但是,在1.1.1和1.2之间启动了另一个查询请求。在此期间,两个查询请求同时发起,2.2在1.2之前到达,因此两个查询的总时间消耗仅相当于第一个查询的时间。

并发查询的优点是可以提高进程的利用率,避免阻塞和等待服务器处理查询,缩短多次查询的时间消耗。然而,缺点是显而易见的。要启动N个并发查询,需要建立N个数据库链接,这对于具有数据库连接池的应用程序来说是可以避免的。

退化的

理想情况下,我们希望有n个并发查询,并且花费的总时间等于查询时间最长的查询。然而,并发查询也有可能退化为同步查询。什么事?在图中,如果1.2在2.1.1之前返回,那么并发查询将退化为同步查询,但是成本高于同步查询。

多路技术

启动查询1启动查询2启动查询3 ……等待查询1、查询2和查询3读取查询2结果、读取查询1结果和读取查询3结果。那么,如何等待才能知道何时返回哪些查询结果呢?

调用读取?对于每个查询IO?如果是阻塞IO,会在一个IO上阻塞,其他IO已经返回结果,无法处理。那么,如果是非阻塞IO,不要害怕会在一个IO上被阻塞,这是真的,但是会造成不断的轮询和判断,浪费CPU资源。

在这种情况下,多路复用可用于轮询多个IOs。

用PHP并发查询MySQL

PHP的MySQL(MySQL nd驱动)提供多路轮询IO(MySQL _ poll)和异步查询(MYSQLI _ ASYNC,mysqli _ raise _ async _ query),用于实现并发查询。示例代码:

?PHP $ SQL=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 5,1 ');$ links=[];$ TV=微时间();$tv=爆炸(',$ TV);$ start=$ TV[1]* 1000(int)($ TV[0]* 1000);//链接数据库,并发起异步查询foreach($ SQL as $ SQL){ $ link=MySQL _ connect(' 127。0 .0 .1 ',' root ',' root ',' dbname ',' 3306 ');$link-query($sql,MYSQLI _ ASYNC);//发起异步查询,立即返回$ link[$ link-thread _ id]=$ link;} $ llen=count($ link);$ process=0;do { $ r _ array=$ e _ array=$ reject=$ links;//多路复用轮询IO if(!($ ret=MySQL _ 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))MySQL _ free _ result($ result);} else { } //操作完后,把当前数据链接从待轮询集合中删除unset($ link[$ link-thread _ id]);$ link-close();$ process } foreach($ e _ array as $ link){ die;} foreach($ reject as $ link){ die;} } while($ process $ llen);$ TV=微时间();$tv=爆炸(',$ TV);$ end=$ TV[1]* 1000(int)($ TV[0]* 1000);echo $end - $start,PHP _ EOLmysqli _ poll源码:

#如果ndef PHP _ WIN32 #定义PHP _ select(m,r,w,e,t) select(m,r,w,e,t)# else # include ' WIN32/select。h ' # endif/* { { MYSQlnd _ poll */PHPAPI enum _ func _ statusmy SQL nd _ poll(MYSQlnd * * r _ array,MYSQLND **e_array,MYSQLND * * * dont _ poll,long sec,long usec,int * desc _ num){ struct time val TV;struct time val * TV _ p=NULLfd _ set rfds、wfds、efdsPHP _ socket _ t max _ FD=0;int retval,set=0;int set_count,max _ set _ count=0;DBG _ ENTER(' _ mysqlnd _ poll ');if(秒0 | | usec 0){ PHP _ error _ docref(NULL,E_WARNING,'为一秒钟和/或usec传递的负值');DBG _返回(失败);} FD _ ZERO(rfd);FD _ ZERO(WFD);FD _ ZERO(EFD);//从所有mysqli链接中获取窝链接描述符if (r_array!=NULL){ * don _ poll=mysqlnd _ stream _ array _ check _ for _ ready(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;} set=set _ count }//从所有mysqli链接中获取窝链接描述符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(!set){ PHP _ error _ docref(NULL,E_WARNING,* dont _ poll?传递的所有数组都是空的":"没有传递流数组);DBGFMT(*不要投票?传递的所有数组都是空的":"没有传递流数组);DBG _返回(失败);} PHP_SAFE_MAX_FD(max_fd,MAX _ set _ count);//选择轮询阻塞时间if(usec 999999){ TV。TV _ sec=sec(usec/1000000);TV . TV _ usec=usec % 1000000 } else { TV . TV _ sec=sectv . TV _ usec=usec } TV _ p=TV//轮询,等待多个超正析象管(图像或图标)可读,php_select是挑选的宏定义retval=php_select(max_fd 1,rfds,wfds,efds,TV _ p);if(retval==-1){ PHP _ error _ docref(NULL,E_WARNING,'无法选择[%d]: %s (max_fd=%d '),errno,strerror(errno),max _ FD);DBG _返回(失败);} 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);} //返回可操作的超正析象管(图像或图标)数量* desc _ num=retval;DBG _返回(通过);}并发查询操作结果

为了更直观地看效果,我找了一个1.3亿数据量并且没有优化过的表进行操作。

并发查询的结果:

同步查询的结果:

从结果来看,同步查询的总时间消耗是所有查询时间的累加;并发查询的总耗时实际上是这里查询时间最长的一个(同步查询的第四个耗时10秒,与并发查询的总耗时一致),并发查询的查询顺序与结果到达的顺序不同。

几种短时查询的比较

与几个查询时间短sql相比

测试1并发查询的结果(也计算数据库链接时间):

同步查询的结果(也计算数据库链接时间):

测试2并发查询的结果(不计算数据库链接时间):

从结果来看,并发查询测试1并没有受益。根据同步查询,每次查询大约需要3-4 ms,但是如果不计算数据库链接时间(同步查询只有一个数据库链接),并发查询的优势就可以再次体现出来。

标签

讨论了如何用PHP实现并发查询MySQL,并从实验结果中直观地了解到并发查询的优缺点。在优化的sql查询中,建立数据库连接的时间仍然占很大比例。#没有连接池。你想要什么

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

更多资讯
游戏推荐
更多+