SQL查询中in、exists、not in、not exists的用法与区别
1、in和exists
in是把外表和内表作hash(字典集合)连接,而exists是对外表作循环,每次循环再对内表进行查询。一直以来认为exists比in效率高的说法是不准确的,如果查询的两个表大小相当,那么用in和exists差别不大;如果两个表中一个较小一个较大,则子查询表大的用exists,子查询表小的用in。
例如:表A(小表),表B(大表)
方式一:索引使用
1)select * from A where id in(select id from B) -->效率低,用到了A表上id列的索引
2)select * from A where exists(select id from B where id=A.id) -->效率高,用到了B表上id列的索引
3)select * from B where id in(select id from A) -->效率高,用到了B表上id列的索引
4)select * from B where exists(select id from A where id=B.id) -->效率低,用到了A表上id列的索引
方式二:遍历使用
1)in()只执行一次,它查出B表中的所有id字段并缓存起来。然后检查A表的id是否与B表中的id相等,如果相等则将A表的记录加入结果集中,直到遍历完A表的所有记录。
它的查询过程类似于以下代码的执行过程:
List resultSet = {};
Array A=(select * from A);
Array B=(select id from B);
for(int i=0;i<A.length;i++) {
for(int j=0;j<B.length;j++) {
if(A[i].id==B[j].id) {
resultSet.add(A[i]);
break;
}
}
}
return resultSet;
可以看出,当B表数据较大时不适合使用in(),因为它会把B表数据全部遍历一次。
如:A表有10000条记录,B表有1000000条记录,那么最多有可能遍历10000*1000000次,效率很差。
如:A表有10000条记录,B表有100条记录,那么最多有可能遍历10000*100次,遍历次数大大减少,效率大大提升。
结论:in()适合B表比A表数据小的情况
2)exists()会执行A.length次,它并不缓存exists()结果集,因为exists()结果集的内容并不重要,重要的是其内查询语句的结果集空或者非空,空则返回false,非空则返回true。
它的查询过程类似于以下代码的执行过程:
List resultSet={};
Array A=(select * from A);
for(int i=0;i<A.length;i++) {
if(exists(A[i].id) { //执行select id from B where B.id=A.id是否有记录返回
resultSet.add(A[i]);
}
}
return resultSet;
当B表比A表数据大时适合使用exists(),因为它没有那么多遍历操作,只需要再执行一次查询就行。
如:A表有10000条记录,B表有1000000条记录,那么exists()会执行10000次去判断A表中的id是否与B表中的id相等。
如:A表有10000条记录,B表有100000000条记录,那么exists()还是执行10000次,因为它只执行A.length次,可见B表数据越多,越适合exists()发挥效果。
再如:A表有10000条记录,B表有100条记录,那么exists()还是执行10000次,还不如使用in()遍历10000*100次,因为in()是在内存里遍历比较,而exists()需要查询数据库,我们都知道查询数据库所消耗的性能更高,而内存比较很快。
结论:exists()适合B表比A表数据大的情况。
当A表数据与B表数据一样大时,in与exists效率差不多,可任选一个使用。
2、not in 和not exists
not in 逻辑上不完全等同于not exists,如果你误用了not in,小心你的程序存在致命的bug。
请看下面的例子:
create table A1 (c1 int,c2 int);
create table A2 (c1 int,c2 int);
insert into A1 values(1,2);
insert into A1 values(1,3);
insert into A2 values(1,2);
insert into A2 values(1,null);
select * from A1 where c2 not in(select c2 from A2); -->执行结果:无(null)
select * from A1 where not exists(select c2 from A2 where A2.c2=A1.c2); -->执行结果:1 3
正如所看到的,not in出现了不期望的结果集,存在逻辑错误。使用not in(它会调用子查询),而使用not exists(它会调用关联子查询)。如果子查询中返回的任意一条记录含有空值,则查询将不返回任何记录。如果子查询字段有非空限制,这时可以使用not in。
如果查询语句使用了not in,那么对内外表都进行全表扫描,没有用到索引;而not exists的子查询依然能用到表上的索引。所以无论哪个表大,用not exists都比not in 要快。
3、in 和 =
select name from employee where name in('张三','李四','王五');
与
select name from employee where name='张三' or name='李四' or name='王五';
的结果是相同的。
4.exists防止插入重复记录
有时需要插入非重复记录,在Mysql中可以使用ignore关键字来忽略已有记录,但是其只能通过主键忽略,不能根据自定义条件忽略。
其语法为:insert ignore into tableName (column1,column2,……) values (value1,value2,……);
但是其他数据库不一定提供类似ignore关键字,所以可以使用exists条件句防止插入重复记录。
insert into A (name,age) select name,age from B where not exists (select 1 from A where A.id=B.id);
5.关于exists更多说明
exists用于检查子查询返回的结果集是否为空,该子查询实际上并不返回任何数据,而是返回值true或false。
语法: exists subQuery
参数: subQuery 是一个受限的 select 语句 (不允许有 compute 子句和 into 关键字)。
结果类型: boolean 如果子查询包含行,则返回 true ,否则返回 false 。
结论:select * from A where exists (select 1 from B where A.id=B.id);
一种通俗的可以理解为:将外查询表的每一行,代入内查询作为检验,如果内查询返回的结果集非空,则exists子句返回true,这一行方可作为外查询的结果行,否则不能作为结果。
--------以上sql内容根据网上提供的资料整理出的结果,均适用与Mysql、Sql Server、Oracle。
SQL查询中in、exists、not in、not exists的用法与区别的更多相关文章
- 一个简单的例子让你很轻松地明白JavaScript中apply、call、bind三者的用法及区别
JavaScript中apply.call.bind三者的用法及区别 引言 正文 一.apply.call.bind的共同用法 二. apply 三. call 四. bind 五.其他应用场景 六. ...
- SQL查询中in和exists的区别分析
select * from A where id in (select id from B); select * from A where exists (select 1 from B where ...
- SQL 查询中not in 与 not exists 的区别
1.in和exists in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询,一直以来认为exists比in效率高的说法是不准确的.如果查询的两个表 ...
- 在sql查询中为了提高查询效率,我们常常会采取一些措施对查询语句进行sql优化,下面总结的一些方法,有需要的可以参考参考。
转载https://www.cnblogs.com/zhang-bo/p/9138151.html 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建 ...
- SQL查询中关键词的执行顺序
写在前面:最近的工作主要是写SQL脚本,在编写过程中对SQL的执行和解析过程特别混乱不清,造成了想优化却无从下手.为此专门在网上找博文学习,并做了如下总结. 1.查询中常用到的关键词有: SELECT ...
- SQL查询中关键字的执行顺序
SQL语句中的每个关键字都按照顺序往下执行,而每一步操作会生成一个临时表,最后的临时表就是最终结果: FROM <left_table>:from子句返回初始结果集 <join_ty ...
- SQL语句中过滤条件放在on、where、having的区别和联系
摘要:SQL语句中,过滤条件放在不同筛选器on.where和having的区别和联系. 综述 在<SQL语句中过滤条件放在on和where子句中的区别和联系>中,介绍了多表关联SQL语 ...
- SQL查询中连接--学习
一.开头说 不出意外,还是先说下SQL中所有的联接类型: 内连接.外连接(左连接.右连接 .全连接).交叉连接 然后接下来就是依次学习下各种连接的使用效果 二.各种连接秀 首先准备两张表 学生表: ...
- sql查询中datetime显示的格式为yyyy-DD-mm
datetime数据库中保存的形式为2008/9/29 星期一 上午 12:00:00,希望界面显示2008-09-29,则可以用到以下sql语句. ),kgrq, ),),jhjgrq, ),'/' ...
随机推荐
- 可伸缩性最佳实践:来自eBay的经验
看到一篇关于系统可伸缩性(可扩展)的文章,eBay的架构师Randy Shoup写的,原文出处没找到,就不写转载的地址了.根据自己的理解对文章有修改剪切的地方. 在eBay,可伸缩性是我们每天奋力抵抗 ...
- java API:AtomicInteger
An int value that may be updated atomically. See the java.util.concurrent.atomic package specificati ...
- Nodejs·构建web应用
本篇的内容比较多..... 1 首先是从基本的Nodejs服务方面讲述前后端统一语言在web应用中的作用: 2 然后讲了web中基本的知识,从请求方法到路由.从查询字符串到Cookie和Session ...
- [数据库连接池] Java数据库连接池--DBCP浅析.
前言对于数据库连接池, 想必大家都已经不再陌生, 这里仅仅设计Java中的两个常用数据库连接池: DBCP和C3P0(后续会更新). 一. 为何要使用数据库连接池假设网站一天有很大的访问量,数据库服务 ...
- java初学者应掌握的30个基本概念
核心提示:OOP中唯一关系的是对象的接口是什么,就像计算机的销售商她不管电源内部结构 是怎样的,他只关系能否给你提供电就行了,也就是只要知道can or not而不是how and why. 基本概念 ...
- fir.im Weekly - Swift 3.0 的迁移适配指南
无论你是移动开发者,还是桌面端开发者,或者正在IoT领域探索的技术人员,那么应该更加关注 iDev 全平台开发者大会,也许是后半年 iOS 开发者最盛大的技术盛宴.既有知名公司带来专业视野,又有从 S ...
- salesforce 零基础学习(十六)Validation Rules & Date/time
上一篇介绍的内容为Formula,其中的Date/time部分未指出,此篇主要介绍Date/time部分以及Validation rules. 本篇参考PDF: Date/time:https://r ...
- Java基础-接口中国特色社会主义的体制中有这样的现象:地方省政府要坚持党的领导和按 照国务院的指示进行安全生产。请编写一个java应用程序描述上述的体制现象。 要求如下: (1)该应用程序中有一个“党中央”接口:CentralPartyCommittee,该接口中 有个“坚持党的领导”方法:void partyLeader() (2)该应用程序中有一个“国务院”抽象类:StateCouncil,
36.中国特色社会主义的体制中有这样的现象:地方省政府要坚持党的领导和按 照国务院的指示进行安全生产.请编写一个java应用程序描述上述的体制现象. 要求如下: (1)该应用程序中有一个“党中央”接口 ...
- 使用SSIS进行数据清洗
简介 OLTP系统的后端关系数据库用于存储不同种类的数据,理论上来讲,数据库中每一列的值都有其所代表的特定含义,数据也应该在存入数据库之前进行规范化处理,比如说"age"列 ...
- IO流-文件管理
File f = new File(“test.txt”); File的构造器不会在文件不存在的情况下新建一个文件,从File对象中创建文件是由文件流的构造器或File类的createNewFile方 ...