mysql中exists 和in的区别是什么

65次阅读
没有评论

共计 2953 个字符,预计需要花费 8 分钟才能阅读完成。

今天就跟大家聊聊有关 mysql 中 exists 和 in 的区别是什么,可能很多人都不太了解,为了让大家更加了解,丸趣 TV 小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

MySQL 中 in 和 exists 的性能优劣以及各自的检索数据的过程,以下面的语句为例子:

select * from user a where name= liuwenhe and exists (select stuid from department b where depname= yunwei and a.stuid =b.stuid);

select * from user where name= liuwenhe and stuid in (select stuid from department where depname= yunwei

MySQL exists 和 in 检索数据的过程:

1. 首先说下 exists 检索过程,

注意其中 A 代表 (user a where name= liuwenhe) 的结果集,B 代表 (department b where depname= yunwei) 的结果集:

exists 对外表 A 用 loop 逐条查询,每次查询都会去验证 exists 的条件语句(也就是 exists 后面括号里面的语句),当 exists 里的条件语句能够返回记录行时(只要能返回结果即可,不管你查询的是什么内容!!!),条件就为真,就会返回当前 loop 到的 A 的这条记录,反之如果 exists 里的条件语句不能返回记录行,条件为假,则当前 loop 到的 A 的这条记录被丢弃,注意:exists 的条件就像一个 bool 条件,当能返回结果集则为 true,不能返回结果集则为 false;

对于 exists 的检索过程可以用下面的脚本概括:

for ($i = 0; $i count(A); $i++) {

$a = get_record(A, $i); #从 A 表逐条获取记录

if (B.id = $a[id]) #如果子条件成立,即返回 true

$result[] = $a;}

return $result;

例如:

select * from user where exists (select stuid from department where depname= yunwei

对 user 表的记录逐条取出,由于 exists 条件中的 select stuid from department where depname= yunwei 永远能返回记录行,那么 user 表的所有记录都将被加入结果集,所以与 select * from user; 是一样的

例如:

select * from user where exists (select stuid from department where depname= yunwei+

not exists 与 exists 相反,也就是当 exists 条件有结果集返回时,loop 到的记录将被丢弃,否则将 loop 到的记录加入结果集

总的来说,如果 user 表结果集有 n 条记录,那么 exists 查询就是将这 n 条记录逐条取出,然后判断 n 遍 exists 条件。

2. 关于 in 子查询的检索过程:

MySQL 先将子查询结果存入临时表 T(可能在内存中,也可能磁盘中),确保子查询只执行一次,该表不记录重复数据且采用哈希索引遍历数据,然后通过 T 表的数据去遍历外表,通过关联关系得到外表的需要的数据,in 查询相当于多个 or 条件的叠加,这个比较好理解,比如下面的查询

select * from user where userId in (1, 2, 3);

等效于

select * from user where userId = 1 or userId = 2 or userId = 3;

not in 与 in 相反,如下

select * from user where userId not in (1, 2, 3);

等效于

select * from user where userId != 1 and userId != 2 and userId != 3;

总的来说,in 查询就是先将子查询条件的记录全都查出来,假设结果集为 B,共有 m 条记录,

然后在将子查询条件的结果集分解成 m 个,再进行 m 次主查询,值得一提的是,in 查询的子条件返回结果必须只有一个字段,例如

select * from user where userId in (select id from B);

而不能是

select * from user where userId in (select id, age from B);

而 exists 就没有这个限制

exists 和 in 的性能

select * from user a where name= liuwenhe and exists (select stuid from department b where depname= yunwei and a.stuid =b.stuid);

select * from user where name= liuwenhe and stuid in (select stuid from department where depname= yunwei

1)根据前面介绍的检索数据的过程,可以知道,针对上面的两条 sql 中 exists 这种方式,是需要遍历 user 表 name= liuwenhe 的所有数据行 N,并且判断 exists 条件 N 次; 并且如果 department 表的 stuid 有索引,exists 子查询可以使用连接关系 (也就是 stuid) 上的索引; 所以 exists 方式适合 user 表的结果集小,子查询的结果集大的情况; 子查询可以使用关联关系列上的索引,所以效率高,故内表大的适合使用 exists;

2)not exists 类似于 exists 的遍历方式,也是 loop 外表,然后判断 exists 条件

3)in 是把外表 user 结果集和内表 department 结果集做 hash 连接(应该说类似 hash join,因为 MySQL 不支持 hash join 的方式),先查询内表 department 结果集,再把内表结果集与外表结果集匹配,对外表可以使用关系索引(也就是 stuid 列上的索引),而内表结果集多大都需要查询,也就是说 department where depname= yunwei 的结果集 D 多大,都得遍历全部的 D,不可避免,故外表大的使用 in,可加快效率。主查询可以使用关联关系列上的索引,所以效率高,故外表结果集合大的适合使用 in;

3)如果用 not in,和 in 一样,内表结果集需要全部扫描,由于 not in,所以外表的结果集也需要权标扫描,都无法使用关系列上的索引(这种!= 的范围查询无法使用任何索引),效率低,可考虑使用 not exists,也可使用 A left join B on A.id=B.id where B.id is null 进行优化。

总结:

exists 先对外表结果集 loop 循环再对内表结果集进行查询。一直大家都认为 exists 比 in 语句的效率要高,这种说法其实是不准确的。这个是要区分环境的。如果查询的两个表大小相当,那么用 in 和 exists 差别不大。如果两个表中一个较小,一个是大表,则子查询表结果集大的用 exists,如果外表结果集大的则适合使用 in,然后就是网络中说的外表的和内表大的说法也不准确,应该是外表结果集和内表结果集合的大小,至于结果集前面已经解释过了。

看完上述内容,你们对 mysql 中 exists 和 in 的区别是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注丸趣 TV 行业资讯频道,感谢大家的支持。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-04发表,共计2953字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)