MySQL5.7和8.0中in和exists关键字

之前看了网上很多关于in和exists性能相关的博客,但总感觉自己测试的结果和他们说的不太一样,所以写下这篇博客,记录下自己测试后得出的总结。特别强调,MySQL5.7和8.0中对这两个关键字有不同的优化,所以我要分开两个版本来讨论。

数据准备

我准备了一张tb_class表和一张tb_stu表
在这里插入图片描述
在这里插入图片描述
注:600个班级,12万个学生。tb_stu是大表,tb_class是小表。为了避免索引优化带来的影响,所以我两张表的id都没有设置主键和索引。

MySQL5.7测试

测试查询效率

我们首先测试一下当外层表时小表的时候,in和exists谁的效率比较高。

在这里插入图片描述
在MySQL5.7中,当外层的表是小表的时候,in的效率会优于exists。

用explain看一下两个sql的执行计划
在这里插入图片描述
从执行计划中看到,exists语句中的select_type是 DEPENDENT SUBQUERY ,我认为性能的消耗主要是在这里,因为 DEPENDENT SUBQUERY 循环嵌套子查询,其效率可想而知。

那么当外层的表时大表的时候,in和exists的效率又是谁比较高呢?

在MySQL5.7中,当外层的表是大表的时候,in的效率依然高于exists。

在这里插入图片描述
可以看到当外层的表是大表的时候,执行效率就非常低了,但是in的效率依旧高于exists。
使用explain查看一下两个sql的执行计划

在这里插入图片描述
经过以上的测试,我发现:外层表不论是大表还是小表,in的效率都要高于exists。网上说什么小表驱动大表,感觉那帮人也没真正自己测试过。

查询效率低的优化策略

从上面的测试我们可以看出来,当大表的数据量超过10W+时,查询效率已经开始变低了(我把大于2秒的查询定为慢查询)。
那么优化方案是什么呢,我的策略是加索引。
我们先在tb_stuclass_id字段上加上btree索引
添加上索引之后,再来观察一下外层表是小表时候的查询效率

在这里插入图片描述

加上索引之后的效果就非常明显了,原先exists查询耗时2s多,现在只耗时0.004s

在这里插入图片描述
通过explain可以发现,rows从原来的12w+变成了只有130。

我们再来对比一下外层表是大表的时候,索引是否能有效。
在这里插入图片描述

震惊!!!exists居然还是耗时8s多!!!
我猜测原因是:当使用exists时,外层表的索引无法在子查询中生效
查看explain的结果
在这里插入图片描述

MySQL8.0测试

测试查询效率

我将数据库换成MySQL8.0,先测试一下外层表是小表的时候,in和exists的查询效率
在这里插入图片描述
我们发现,在MySQL8.0中,in和exists的执行效率是一样高的
甚至我使用explain查看的执行计划都是一样的。

在这里插入图片描述
将外层表改为大表,再测试一下:

在这里插入图片描述

查询效率依旧一样快有木有!
他俩的explain执行计划也是一样的:
在这里插入图片描述

最后总结

  1. 在MySQL5.7中,in的效率要高于exists,但在8.0中,他俩的效率是一样的
  2. 在MySQL5.7中,外层表的字段使用in查询不会使这个字段的索引失效,但是如果使用exists就会使索引失效了
  3. MySQL8.0的查询效率真的比5.7好很多,如果是新项目的话,强烈建议使用MySQL8.0
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值