JOIN与IN的比拟-MySQL性能优化 (join与in的区别)
当天发现一篇很无心思的文章,经常使用查问时,是经常使用join好,还是间接in更好,这个大家上班时经常遇到。
为了繁难大家检查,文章我从新启动了排版。
我没有间接用作者的论断,觉得或者会误导读者,而是依据实验结果,给出我自己的倡导。
不BB,上目录:
图片
01背景
事件是这样的,去年入职的新公司,之后在代码review的时刻被提出说,不要写join,join耗性能还是慢来着,过后也是真的没有多想,那就写in好了。
最近发现in的数据量过大的时刻会造成sql慢,甚至sql太长,间接报错了。
这次来浅究一下,究竟是in好还是join好,仅目前认知探寻,有不对之处欢迎斧正。
以下实验仅在本机电脑实验。
02表结构
2.1用户表
图片
CREATETABLE`user`(`id`intNOTNULLAUTO_INCREMENT,`name`varchar(64)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNOTNULLCOMMENT'姓名',`gender`smallintDEFAULTNULLCOMMENT'性别',`mobile`varchar(11)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNOTNULLCOMMENT'手机号',`create_time`datetimeNOTNULLCOMMENT'创立期间',PRIMARYKEY(`id`),UNIQUEKEY`mobile`(`mobile`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=1005DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_general_ci
2.2订单表
图片
CREATETABLE`order`(`id`intunsignedNOTNULLAUTO_INCREMENT,`price`decimal(18,2)NOTNULL,`user_id`intNOTNULL,`product_id`intNOTNULL,`status`smallintNOTNULLDEFAULT'0'COMMENT'订单形态',PRIMARYKEY(`id`),KEY`user_id`(`user_id`),KEY`product_id`(`product_id`))ENGINE=InnoDBAUTO_INCREMENT=202DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_general_ci
03千条数据状况
数据量:用户表插一千条随机生成的数据,订单表插一百条随机数据
要求:查下一切的订单以及订单对应的用户
耗时权衡目的:多表衔接查问老本=一次性驱动表老本+从驱动表查出的记载数*一次性被驱动表的老本
selectorder.id,price,user.namefromorderjoinuseronorder.user_id=user.id;
图片
selectid,price,user_idfromorder;
图片
selectnamefromuserwhereidin(8,11,20,32,49,58,64,67,97,105,113,118,129,173,179,181,210,213,215,216,224,243,244,251,280,309,319,321,336,342,344,349,353,358,363,367,374,377,380,417,418,420,435,447,449,452,454,459,461,472,480,487,498,499,515,525,525,531,564,566,580,584,586,592,595,610,633,635,640,652,658,668,674,685,687,701,718,720,733,739,745,751,758,770,771,780,806,834,841,856,856,857,858,882,934,942,983,989,994,995);
其中in的是order查进去的一切用户id。
图片
如此看来,离开查和join查的老本并没有相差许多。
3.3并发场景
重要用原生写了脚本,用ab启动10个同时的恳求,看下期间,启动比拟。
>ab-n100-c10//口头脚本
上方是join查问的口头脚本:
$mysqli=newmysqli('127.0.0.1','root','root','test');if($mysqli->connect_error){die('ConnectError('.$mysqli->connect_errno.')'.$mysqli->connect_error);}$result=$mysqli->query('selectorder.id,price,user.`name`from`order`joinuseronorder.user_id=user.id;');$orders=$result->fetch_all(MYSQLI_ASSOC);var_dump($orders);$mysqli->close();
图片
上方是in查问的口头脚本:
$mysqli=newmysqli('127.0.0.1','root','root','test');if($mysqli->connect_error){die('ConnectError('.$mysqli->connect_errno.')'.$mysqli->connect_error);}$result=$mysqli->query('select`id`,price,user_idfrom`order`');$orders=$result->fetch_all(MYSQLI_ASSOC);$userIds=implode(',',array_column($orders,'user_id'));//失掉订单中的用户id$result=$mysqli->query("select`id`,`name`from`user`whereidin({$userIds})");$users=$result->fetch_all(MYSQLI_ASSOC);//失掉这些用户的姓名//将id做数组键$userRes=[];foreach($usersas$user){$userRes[$user['id']]=$user['name'];}$res=[];//整合数据foreach($ordersas$order){$current=[];$current['id']=$order['id'];$current['price']=$order['price'];$current['name']=$userRes[$order['user_id']]?:'';$res[]=$current;}var_dump($res);//封锁mysql衔接$mysqli->close();
图片
看期间的话,清楚join更快一些。
04万条数据状况
user表如今10000条数据,order表10000条试下。
图片
order耗时:
图片
user耗时:
图片
4.3并发场景
join耗时:
图片
in耗时:
图片
数据量到达万级别,非并发场景,in更快,并发场景join更快。
05十万条数据状况
随机拔出后user表十万条数据,order表一百万条试下。
图片
order耗时:
图片
user耗时:
order查进去的结果过长了...
5.3并发场景
join耗时:
图片
in耗时:
图片
数据量到达十万/百万级别,非并发场景,in过长,并发场景join更快。
06总结
实验论断:
上方是楼仔给出的一些倡导。
当数据量比拟小时,倡导用in,只管两者的性能差不多,然而join会参与sql的复杂度,后续再变卦,会十分费事。
当数据量比拟大时,倡导用join,重要还是出于查问性能的思考。
不过经常使用join时,小表驱动大表,必定要建设索引,join的表最好不要超越3个,否则性能会十分差,还会大大参与sql的复杂度,十分不利于后续性能裁减。
在SQL联表查询的时候,in和inner join各有什么优点?
in后面跟的是一些确定的数据或值,inner join是内连接,联表时的一种
在SQL联表查询的时候,in和inner join各有什么优点?
大概举例如下:比如A1表 100W行 A2表50W行select a.* from A1 a where 1 in (select 1 from A2 b where 2=xxx);select a.* from A1 a where exists (select x from A2 b where 2=xxx and 1=1);select a.* from A1 a,A2 b where 2=xxx and 1=1在(select from A2 b where 2=xxx)的结果集比较小的情况下(比如只有几十条)用in的效率高于关联,如果结果集比较大的情况下则用join的效率高于用in,这里我还列举了exists,这个效率类似于join也是结果集大的情况下适用,至于两者的拐点还需要你在执行计划和统计信息当中去观察以便确定出最优的sql语句。
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。