网上很多文章都说exists的效率要高于in,其实不然。只能说不一定,exists和in各有各的使用场景,下面我们总结一下MySQL中exists和in的区别:
in关键字
select * from A where id in (select id from B)
#等价于
- for select id from B:先执行;
- 子查询 for select id from A where A.id = B.id:再执行外面的查询;
执行过程:in是先查询内表【select id from B】,再把内表结果与外表【select * from A where id in …】匹配,对外表使用索引,而内表多大都需要查询,不可避免,故外表大的使用in,可加快效率。
小总结:当A表的数据集大于B表的数据集时,用in优于exists。【in适合外部表数据大于子查询的表数据的业务场景】
exists关键字
语法格式:
select ... from table where exists (subquery);
可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果(TRUE 或者 FALSE)来决定主查询数据结果是否得到保留。
如下:
select * from A where exists (select 1 from B where B.id = A.id)
#等价于
- for select id from A:先执行外层的查询;
- for select id from B where B.id = A.id:再执行子查询;
执行过程:exists是对外表【select * from A where exists …】做loop循环,每次loop循环再对内表(子查询)【select 1 from B where B.id = A.id】进行查询,那么因为对内表的查询使用的索引(内表效率高,故可用大表),而外表有多大都需要遍历,不可避免(所以尽量用小表),故内表大的使用exists,可加快效率。
例如:
select * from A where exists (select 1 from B where B.id = A.id)
1)、表A中100000条数据,表B中100条数据,那么查询数据库的次数 = 1(表A查一次) + 100000(子查询:查询表B的次数) ,一共 100001次;
2)、表A中 100条数据,表B中100000条,查询数据库次数 = 1(表A查一次) + 100(子查询次数),一共 101次;
可见,只有当子查询的表数量远远大于外部表数据的时候,用exist查询效率好于in;
提示
1. EXISTS (subquery) 只返回 True 或 False , 因此查询的 SELET * 也可以是SELET 1 或其他,官方说法是执行时会忽略SELECT 清单, 因此没有区别;
2. EXISTS 子查询的实际执行过程可能经过了优化而不是我们理解的逐条比对,如果担忧效率问题,可以进行实际检验以确定是否有效率问题;
3. EXISTS 子查询往往也可以使用条件表达式、其他子查询或者 JOIN 来代替,何种最优化需要具体分析;
> 小总结:当A表的数据集小于B表的数据集时,用exists优于in。【exist适合子查询中表数据大于外查询表中数据的业务场景】
总结
select * from A where id in (select id from B)
select * from A where exists (select 1 from B where B.id = A.id)
当A表的数据集大于B表的数据集时,用in 优于 exists;
当A表的数据集小于B表的数据集, 用 exists 优于 in【注意: A与B表的id 字段应该建立索引】;
如果查询的两个表大小相当,那么用in和exists差别不大。如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in;