你的位置:首页 > 数据库

[数据库]oracle中的exists 和not exists 用法 in与exists语句的效率问题


博文来源(oracle中的exists 和not exists 用法):http://chenshuai365-163-com.iteye.com/blog/1003247

博文来源(  in与exists语句的效率问题):http://www.cnblogs.com/iceword/archive/2011/02/15/1955337.html

(一)

exists (sql 返回结果集为真)
not exists (sql 不返回结果集为真)
如下:
表A
ID NAME

1    A1
2    A2
3  A3

表B
ID AID NAME
1    1 B1
2    2 B2
3    2 B3

表A和表B是1对多的关系 A.ID => B.AID

 1 SELECT ID,NAME FROM A WHERE EXIST (SELECT * FROM B WHERE A.ID=B.AID) 2 执行结果为 3 1 A1 4 2 A2 5 原因可以按照如下分析 6 SELECT ID,NAME FROM A WHERE EXISTS (SELECT * FROM B WHERE B.AID=1) 7 --->SELECT * FROM B WHERE B.AID=1有值返回真所以有数据 8  9 SELECT ID,NAME FROM A WHERE EXISTS (SELECT * FROM B WHERE B.AID=2)10 --->SELECT * FROM B WHERE B.AID=2有值返回真所以有数据11 12 SELECT ID,NAME FROM A WHERE EXISTS (SELECT * FROM B WHERE B.AID=3)13 --->SELECT * FROM B WHERE B.AID=3无值返回真所以没有数据14 15 NOT EXISTS 就是反过来16 SELECT ID,NAME FROM A WHERE NOT EXIST (SELECT * FROM B WHERE A.ID=B.AID)17 执行结果为18 3 A3 

 


(二)SQL中IN,NOT IN,EXISTS,NOT EXISTS的用法和差别:

 

  IN 关键字使您得以选择与列表中的任意一个值匹配的行。确定给定的值是否与子查询或列表中的值相匹配。  (1)获得居住在 California、Indiana 或 Maryland 州的所有作者的姓名和州的列表时,就需要下列查询:  SELECT ProductID, ProductName FROM Northwind.dbo.Products WHERE CategoryID = 1 OR CategoryID = 4 OR CategoryID = 5  然而,如果使用 IN,少键入一些字符也可以得到同样的结果:  SELECT ProductID, ProductName FROM Northwind.dbo.Products WHERE CategoryID IN (1, 4, 5)  IN 关键字之后的项目必须用逗号隔开,并且括在括号中。  (2)下列查询在 titleauthor 表中查找在任一种书中得到的版税少于 50% 的所有作者的 au_id,然后从 authors 表中选择 au_id 与titleauthor 查询结果匹配的所有作者的姓名:  SELECT au_lname, au_fname FROM authors WHERE au_id IN (SELECT au_id FROM titleauthor WHERE royaltyper <50)  结果显示有一些作者属于少于 50% 的一类。  NOT IN:通过 NOT IN 关键字引入的子查询也返回一列零值或更多值。  以下查询查找没有出版过商业书籍的出版商的名称。  SELECT pub_name FROM publishers WHERE pub_id NOT IN (SELECT pub_id FROM titles WHERE type = 'business')  使用 EXISTS 和 NOT EXISTS 引入的子查询可用于两种集合原理的操作:交集与差集。   (1) 两个集合的交集包含同时属于两个原集合的所有元素。   (2)差集包含只属于两个集合中的第一个集合的元素。   EXISTS:指定一个子查询,检测行的存在。  本示例所示查询查找由位于以字母 B 开头的城市中的任一出版商出版的书名:  SELECT DISTINCT pub_name FROM publishers WHERE EXISTS (SELECT * FROM titles WHERE pub_id = publishers.pub_id AND type ='business')  SELECT distinct pub_name FROM publishers WHERE pub_id IN (SELECT pub_id FROM titles WHERE type = 'business')
  两者的区别:  EXISTS:后面可以是整句的查询语句如:SELECT * FROM titles  IN:后面只能是对单列:SELECT pub_id FROM titles  NOT EXISTS:  例如,要查找不出版商业书籍的出版商的名称:  SELECT pub_name FROM publishers WHERE NOT EXISTS (SELECT * FROM titles WHERE pub_id = publishers.pub_id AND type =  'business')  下面的查询查找已经不销售的书的名称:  SELECT title FROM titles WHERE NOT EXISTS (SELECT title_id FROM sales WHERE title_id = titles.title_id)

 

(三)In 于 EXISTS 的效率问题

select * from Awhere 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表数据小的情况select a.* from A awhere 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效率差不多,可任选一个使用.