转自https://www.cnblogs.com/liyasong/p/sql_in_exists.html 和 http://blog.csdn.net/lick4050312/article/details/4476333javascript
表展现html
查询中涉及到的两个表,一个user和一个order表,具体表的内容以下:java
user表:sql
order表:数据库
in缓存
1、肯定给定的值是否与子查询或列表中的值相匹配。in在查询的时候,首先查询子查询的表,而后将内表和外表作一个笛卡尔积,而后按照条件进行筛选。因此相对内表比较小的时候,in的速度较快。oop
具体sql语句以下:性能
1 SELECT 2 * 3 FROM 4 `user` 5 WHERE 6 `user`.id IN ( 7 SELECT 8 `order`.user_id 9 FROM 10 `order` 11 )
这条语句很简单,经过子查询查到的user_id 的数据,去匹配user表中的id而后获得结果。该语句执行结果以下:this
它的执行流程是什么样子的呢?让咱们一块儿来看一下。spa
首先,在数据库内部,查询子查询,执行以下代码:
SELECT `order`.user_id FROM `order`
执行完毕后,获得结果以下:
此时,将查询到的结果和原有的user表作一个笛卡尔积,结果以下:
此时,再根据咱们的user.id IN order.user_id的条件,将结果进行筛选(既比较id列和user_id 列的值是否相等,将不相等的删除)。最后,获得两条符合条件的数据。
2、select * from A where id in(select id from B)
以上查询使用了in语句,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表数据小的状况
1、指定一个子查询,检测行的存在。遍历循环外表,而后看外表中的记录有没有和内表的数据同样的。匹配上就将结果放入结果集中。
具体sql语句以下:
1 SELECT 2 `user`.* 3 FROM 4 `user` 5 WHERE 6 EXISTS ( 7 SELECT 8 `order`.user_id 9 FROM 10 `order` 11 WHERE 12 `user`.id = `order`.user_id 13 )
这条sql语句的执行结果和上面的in的执行结果是同样的。
可是,不同的是它们的执行流程彻底不同:
使用exists关键字进行查询的时候,首先,咱们先查询的不是子查询的内容,而是查咱们的主查询的表,也就是说,咱们先执行的sql语句是:
SELECT `user`.* FROM `user`
获得的结果以下:
而后,根据表的每一条记录,执行如下语句,依次去判断where后面的条件是否成立:
EXISTS ( SELECT `order`.user_id FROM `order` WHERE `user`.id = `order`.user_id )
若是成立则返回true不成立则返回false。若是返回的是true的话,则该行结果保留,若是返回的是false的话,则删除该行,最后将获得的结果返回。
2、select a.* from A a where exists(select 1 from B b where a.id=b.id)
以上查询使用了exists语句,exists()会执行A.length次,它并不缓存exists()结果集,由于exists()结果集的内容并不重要,重要的是结果集中是否有记录,若是有则返回true,没有则返回false. 它的查询过程相似于如下过程
List resultSet=[]; Array A=(select * from A)
for(int i=0;i<A.length;i++) { if(exists(A[i].id) { //执行select 1 from B 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效率差很少,可任选一个使用.
in 和 exists的区别: 若是子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in, 反之若是外层的主查询记录较少,子查询中的表大,又有索引时使用exists。其实咱们区分in和exists主要是形成了驱动顺序的改变(这是性能变化的关键),若是是exists,那么之外层表为驱动表,先被访问,若是是IN,那么先执行子查询,因此咱们会以驱动表的快速返回为目标,那么就会考虑到索引及结果集的关系了 ,另外IN时不对NULL进行处理。
in 是把外表和内表做hash 链接,而exists是对外表做loop循环,每次loop循环再对内表进行查询。一直以来认为exists比in效率高的说法是不许确的。
等价语句
SELECT /*+ PARALLEL*/ 'HL',T1.*,SYSDATE,'2017-05' FROM DC_ALL_HL.V_OFFER_INST_INFO T1 WHERE T1.PROD_INST_ID IN ( SELECT PROD_INST_ID FROM AUDI_SAMPLE_HL); SELECT /*+ PARALLEL(T1,50)*/ 'HL',T1.*,SYSDATE,'2017-05' FROM DC_ALL_HL.V_OFFER_INST_INFO T1
WHERE EXISTS (
SELECT * FROM AUDI_SAMPLE_HL AU where T1.PROD_INST_ID = AU.PROD_INST_ID);
若是查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。因此不管那个表大,用not exists都比not in要快。
好比在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHERE EXISTS( SELECT OrderID FROM Orders o WHERE o.CustomerID=c.CustomerID) 这里面的EXISTS是如何运做呢?子查询返回的是OrderId字段,但是外面的查询要找的是CustomerID和CompanyName字段,这两个字段确定不在OrderID里面啊,这是如何匹配的呢?
EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False EXISTS 指定一个子查询,检测 行 的存在。
语法: EXISTS subquery 参数: subquery 是一个受限的 SELECT 语句 (不容许有 COMPUTE 子句和 INTO 关键字)。 结果类型: Boolean 若是子查询包含行,则返回 TRUE ,不然返回 FLASE 。
例表A:TableIn | 例表B:TableEx |
![]() |
![]() |
(一). 在子查询中使用 NULL 仍然返回结果集 select * from TableIn where exists(select null) 等同于: select * from TableIn
(二). 比较使用 EXISTS 和 IN 的查询。注意两个查询返回相同的结果。 select * from TableIn where exists(select BID from TableEx where BNAME=TableIn.ANAME) select * from TableIn where ANAME in(select BNAME from TableEx)
(三). 比较使用 EXISTS 和 = ANY 的查询。注意两个查询返回相同的结果。 select * from TableIn where exists(select BID from TableEx where BNAME=TableIn.ANAME) select * from TableIn where ANAME=ANY(select BNAME from TableEx)
NOT EXISTS 的做用与 EXISTS 正好相反。若是子查询没有返回行,则知足了 NOT EXISTS 中的 WHERE 子句。
结论: EXISTS(包括 NOT EXISTS )子句的返回值是一个BOOL值。 EXISTS内部有一个子查询语句(SELECT ... FROM...), 我将其称为EXIST的内查询语句。其内查询语句返回一个结果集。 EXISTS子句根据其内查询语句的结果集空或者非空,返回一个布尔值。
一种通俗的能够理解为:将外查询表的每一行,代入内查询做为检验,若是内查询返回的结果取非空值,则EXISTS子句返回TRUE,这一行行可做为外查询的结果行,不然不能做为结果。
分析器会先看语句的第一个词,当它发现第一个词是SELECT关键字的时候,它会跳到FROM关键字,而后经过FROM关键字找到表名并把表装入内存。接着是找WHERE关键字,若是找不到则返回到SELECT找字段解析,若是找到WHERE,则分析其中的条件,完成后再回到SELECT分析字段。最后造成一张咱们要的虚表。 WHERE关键字后面的是条件表达式。条件表达式计算完成后,会有一个返回值,即非0或0,非0即为真(true),0即为假(false)。同理WHERE后面的条件也有一个返回值,真或假,来肯定接下来执不执行SELECT。 分析器先找到关键字SELECT,而后跳到FROM关键字将STUDENT表导入内存,并经过指针找到第一条记录,接着找到WHERE关键字计算它的条件表达式,若是为真那么把这条记录装到一个虚表当中,指针再指向下一条记录。若是为假那么指针直接指向下一条记录,而不进行其它操做。一直检索完整个表,并把检索出来的虚拟表返回给用户。EXISTS是条件表达式的一部分,它也有一个返回值(true或false)。
在插入记录前,须要检查这条记录是否已经存在,只有当记录不存在时才执行插入操做,能够经过使用 EXISTS 条件句防止插入重复记录。 INSERT INTO TableIn (ANAME,ASEX) SELECT top 1 '张三', '男' FROM TableIn WHERE not exists (select * from TableIn where TableIn.AID = 7)
EXISTS与IN的使用效率的问题,一般状况下采用exists要比in效率高,由于IN不走索引,但要看实际状况具体使用: IN适合于外表大而内表小的状况;EXISTS适合于外表小而内表大的状况。