`
bianxq
  • 浏览: 91449 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

oracle中关于in和exists,not in 和 not exists、关联子查询、非关联子查询

阅读更多
                oracle中关于in和exists,not in 和 not exists
in和exists
    in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询。
not exists:做NL,对子查询先查,有个虚表,有确定值,所以就算子查询有NULL最终也有值返回
not in:做hash,对子查询表建立内存数组,用外表匹配,那子查询要是有NULL那外表没的匹配最终无值返回。
    一直以来认为exists比in效率高的说法是不准确的。
 
如果查询的两个表大小相当,那么用in和exists差别不大。

如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in:

例如:表A(小表),表B(大表)
1:
select * from A where cc in (select cc from B)
效率低,用到了A表上cc列的索引;
select * from A where exists(select cc from B where cc=A.cc)
效率高,用到了B表上cc列的索引。
 
相反的
2:
select * from B where cc in (select cc from A)
效率高,用到了B表上cc列的索引;
select * from B where exists(select cc from A where cc=B.cc)
效率低,用到了A表上cc列的索引。
 
not in 和not exists
如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;
而not extsts 的子查询依然能用到表上的索引。
所以无论那个表大,用not exists都比not in要快。
一直听到的都是说尽量用exists不要用in,因为exists只判断存在而in需要对比值,所以exists比较快,但看了看网上的一些东西才发现根本不是这么回事。
下面这段是抄的
Select * from T1 where x in ( select y from T2 )
执行的过程相当于:
select *
  from t1, ( select distinct y from t2 ) t2
 where t1.x = t2.y;

select * from t1 where exists ( select null from t2 where y = x )
执行的过程相当于:
for x in ( select * from t1 )
   loop
      if ( exists ( select null from t2 where y = x.x )
      then
         OUTPUT THE RECORD
      end if
end loop

从我的角度来说,in的方式比较直观,exists则有些绕,而且in可以用于各种子查询,而exists好像只用于关联子查询(其他子查询当然也可以用,可惜没意义)。
由于exists是用loop的方式,所以,循环的次数对于exists影响最大,所以,外表要记录数少,内表就无所谓了,而in用的是hash join,所以内表如果小,整个查询的范围都会很小,如果内表很大,外表如果也很大就很慢了,这时候exists才真正的会快过in的方式。
 
not in 和not exists
如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;
而not extsts 的子查询依然能用到表上的索引。
所以无论那个表大,用not exists都比not in要快。

 也就是说,in和exists需要具体情况具体分析,not in和not exists就不用分析了,尽量用not exists就好了。

 

典型的连接类型共有3种:
排序 - - 合并连接(Sort Merge Join (SMJ) )
嵌套循环(Nested Loops (NL) )
哈希连接(Hash Join)

嵌套循环和哈希连接的算法还是有不同,在理论上哈希连接要快过排序和nl,当然实际情况比理论上有复杂的多,不过两者还是有差异的.

 

1 关联子查询与非关联子查询

 关联子查询需要在内部引用外部表,而非关联子查询不要引用外部表。对于父查询中处理的记录来说,一个关联子查询是每行计算一次,然而一个非关联子查询只会执行一次,而且结果集被保存在内存中(如果结果集比较小),或者放在一张oracle临时数据段中(如果结果集比较大)。一个“标量”子查询是一个非关联子查询,返回唯一记录。如果子查询仅仅返回一个记录,那么oracle优化器会将结果缩减为一个常量,而且这个子查询只会执行一次。

/*select * from emp where deptno in (select deptno from dept where dept_name='admin');*/

2.如何选择?

  根据外部查询,以及子查询本身所返回的记录的数目。如果两种查询返回的结果是相同的,哪一个效率更好?

  关联子查询的系统开销:对于返回到外层查询的记录来说,子查询会每次执行一次。因此,必须保证任何可能的时候子查询都要使用索引。

  非关联子查询的系统开销:子查询只会执行一次,而且结果集通常是排好序的,并保存在临时数据段中,其中每一个记录在返回时都会被父级查询引用,在子查询返回大量记录的情况下,将这些结果集排序回增大系统的开销。

  所以:如果父查询只返回较少的记录,那么再次执行子查询的开销不会非常大,如果返回很多数据行,那么直查询就会执行很多次。 如果子查询返回较少的记录,那么为内存中保存父查询的结果集的系统开销不会非常大,如果子查询返回多行,那么需要将结果放在临时段上,然后对数据段排序,以便为负查询中的每个记录服务。

 

3结论:1)在使用一个关联子查询是,使用in 或者 exists子句的子查询执行计划通常都相同

       2)exists子句通常不适于子查询

       3)在外部查询返回相对较少记录时,关联子查询比非关联子查询执行得要更快。

       4)如果子查询中只有少量的记录,则非关联子查询会比关联子查询执行得更快。

4 子查询转化:子查询可以转化为标准连接操作

       1)使用in的非关联子查询(子查询唯一)

          条件:1)在整个层次结构中最底层数据表上定义唯一主键的数据列存在于子查询的select列表中

                2)至少有个定义了唯一主键的数据列在select列表中,而且定义唯一主键的其他数据列都必须有指定的相等标准,不管是直接指定,还是间接指定。

       2)使用exists子句的关联子查询

          条件:对于相关条件来说,该子查询只能返回一个记录。

 

5。not in和not exists调整

  1)not in 非关联子查询:转化为in写法下的minus子句

  2)not exists关联子查询:这种类型的反连接操作会为外部查询中每一个记录进行内部查询,除了不满足子查询中where条件的内部数据表以外,他会过滤掉所有记录。

    可以重写:在一个等值连接中指定外部链接条件,然后添加select distinct

    eg:select distinct ... from a,b where a.col1 = b.col1(+) and b.col1 is null

6。在子查询中使用all any

 

 

1.      1.  简介

本文简要介绍了关联子查询、非关联子查询、IN & EXISTS NOT IN & NOT EXISTS之间的区别;同时对不同数据库版本下CBOIN & EXISTS & NOT IN & NOT EXISTS的处理做了一定的阐述。

2.         os、数据库版本以及测试数据

oswindows 2000 server sp4

dboracle 10.1.0.2

 

 

set time on

set timing on

 

 

drop table outer_large_t

/

create table outer_large_t

(id number,

c1 varchar2(100),

c2 varchar2(100)

)

/

 

 

create index idx_outer_large_t on outer_large_t(id)

/

 

 

drop table outer_small_t

/

create table outer_small_t

as select *from outer_large_t

where 1=2

/

create index idx_outer_small_t_id on outer_small_t(id)

/

 

 

drop table inner_large_t

/

create table inner_large_t

(id number,

c3 varchar2(100),

c4 varchar2(100)

)

/

create index idx_inner_large_t_1 on inner_large_t(id,c3)

/

drop table inner_small_t

/

create table inner_small_t

(id number,

c3 varchar2(100),

c4 varchar2(100)

)

/

create index idx_inner_small_t on inner_small_t(id,c3)

/

 

 

3.      2.关联子查询和非关联子查询

测试数据:

truncate table outer_large_t

/

truncate table inner_large_t

/

 

declare

begin

  for i in 1..50000 loop

    insert into outer_large_t values (i,'test','test');   

  end loop;

  for i in 30000..100000 loop

    insert into inner_large_t values (i,'test','test');   

  end loop;

  commit;

end;

/

 

analyze table outer_large_t compute statistics for table for all indexes

/

analyze table inner_large_t compute statistics for table for all indexes

/

 

非关联子查询形如:

select count(*) from outer_large_t

where id not in

(select id from inner_large_t)

/

子查询与父查询没有关联。

关联子查询形如:

select count(*) from outer_large_t outer_t

where not exists

(select id from inner_large_t where id = outer_t.id)

/

子查询与父查询存在关联id = outer_t.id

非关联子查询对于existsnot exists是没有意义的。

看如下实验:

11:17:00 test@GZSERVER> select count(*) from outer_large_t

11:17:02   2  where id not in

11:17:02   3  (select id from inner_large_t)

11:17:02   4  /

 

 

  COUNT(*)

----------

     29999

 

 

已用时间:  00: 00: 00.04

11:17:02 test@GZSERVER> select count(*) from outer_large_t

11:17:02   2  where id in

11:17:02   3  (select id from inner_large_t)

11:17:02   4  /

 

 

  COUNT(*)

----------

     20001

 

 

已用时间:  00: 00: 00.01

11:17:02 test@GZSERVER> select count(*) from outer_large_t outer_t

11:17:02   2  where not exists

11:17:02   3  (select id from inner_large_t)

11:17:02   4  /

 

 

  COUNT(*)

----------

         0

  

已用时间:  00: 00: 00.00

11:17:02 test@GZSERVER> select count(*) from outer_large_t outer_t

11:17:02   2  where exists

11:17:02   3  (select id from inner_large_t)

11:17:02   4  /

 

  COUNT(*)

----------

     50000

 

 

 

已用时间:  00: 00: 00.00

11:17:03 test@GZSERVER>

非关联子查询使用not exists的话父查询总是返回0,使用exists总是返回父查询的查询结果集。

分享到:
评论

相关推荐

    Oracle In和exists not in和not exists的比较分析

    in和exist的区别 从sql编程角度来说,in直观,exists不直观多一个select, in可以用于各种子查询,而exists好像只用于关联子查询 从性能上来看 exists是用loop的方式,循环的次数影响大,外表要记录数少,内表就...

    exists SQL用法详解、exists和not exists的常用示例

    exists: 括号内子查询sql语句返回结果不为空(即:sql返回的结果为真),子查询的结果不为空这条件成立,执行...提醒:文章中提供了exists和not exists的常用示例,已经经过本人测试,文档中附有测试数据sql和用法sql。

    sql语句优化之用EXISTS替代IN、用NOT EXISTS替代NOT IN的语句

    在子查询中,NOT IN子句将执行一个内部的排序和合并。无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历)。为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT ...

    sql exists和not exists用法

    使用EXISTS(或NOT EXISTS)关键字引入一个子查询时,子查询实际上不产生任何数据;它只返回TRUE或FALS值。 指定一个子查询,检测行的存在。 如果子查询包含行,则返回 TRUE IN效率要差(返回子查询)

    Oracle数据库-- 高级子查询chinese

    通过本章学习,您将可以: 书写多列子查询 子查询对空值的处理 在 FROM 子句中使用子查询 在SQL中使用单列子查询 相关子查询 书写相关子查询 使用子查询更新和删除...使用 EXISTS 和 NOT EXISTS 操作符 使用 WITH 子句

    浅析SQL中WHERE EXISTS子查询.pdf

    浅析SQL中WHERE EXISTS子查询.pdf

    INEXISTS与NOT INNOT EXISTS 的优化原则小结

    1. EXISTS的执行流程 select * from t1 where exists ( select null ...exists的性能区别: 如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in,反之如果外层的主查询记录较少,子查询中的表大,又

    sql not in 与not exists使用中的细微差别

    not exists的子查询,对于子查询不返回行和子查询返回行的查询结果是有区别的 这些细小的差别千万不要被我们所忽视,一旦项目庞大了,想跟踪到具体的错误所花费的时间也是可观的。尽量把这些不必要的错误扼杀在摇篮...

    oracle中not exists对外层查询的影响详解

    这个10g的环境和12c的环境,数据量大致一样,只是有很少部分的不同,但是就是这个很少部分不同,造成了not exists中的子查询返回不同的值,进而对外层查询产生不同的影响。 我们来用如下的代码模拟一下。 初始化数据...

    SQL之EXISTS

    它所在的查询属于相关子查询,即子查询的查询条件依赖于外层父查询的某个属性值,处理过程一般为: 取外层查询的第一个元组,根据它与内层查询相关的属性值处理内层查询,若where子句返回true,则将此元组放入结果表...

    关系代数中“除法”运算与SQL中带有exists子查询的对比教学.pdf

    关系代数中“除法”运算与SQL中带有exists子查询的对比教学.pdf

    数据库子查询

    分为四类介绍数据库子查询: 一、使用比较运算的子查询 二、使用all、any关键字的子查询 三、使用列表运算符的子查询(in 或者 not in) 四、使用exists运算符的子查询

    Oracle高级sql学习与练习

    9、相关子查询和非相关子查询 10、增强GROUP BY 11、分析函数(ANALYTICAL FUNCTIONS) 12、ROWID的使用 13、ORACLE 10G正则表达式 14、使用HINT 15、PARITION分区 16、并行操作 17、扩展DDL和DML语句 18、MODEL语句...

    精通SQL 结构化查询语言详解

    10.2.4 EXISTS子查询实现两表交集  10.2.5 SOME/ALL子查询  10.2.6 UNIQUE子查询  10.3 相关子查询  10.3.1 使用IN引入相关子查询  10.3.2 比较运算符引入相关子查询 10.3.3 在HAVING子句中使用相关子...

    MySQL中exists关键字和in的区别有那些? SQL语句优化有那些方法? 查询速度很慢应该怎么办?

    一、exists和in有何区别如下?  exists使用循环的方式,由outer表的记录数决定循环的次数,对于exists的影响最大,所以,外表的记录越小,子查询结果集较大时适用于exists; in 先执行子查询,子查询的结果返回去重...

    【3.18数据库作业8】SQL练习8 – SELECT(嵌套查询EXISTS、集合查询、基于派生表的查询)

    -带有EXISTS谓词的子查询 -集合查询 -基于派生表的查询 -Select总结 下午上次课学到了嵌套查询-3 今天我们来看一下 带有EXISTS谓词的子查询 3/20 15:30 EXISTS谓词: 存在量词 ∃ 带有EXISTS谓词的子查询不返回任何...

    Oracle数据库、SQL

    十一、 非关联子查询 19 11.1语法 19 11.2子查询的执行过程 19 11.3常见错误 19 11.4子查询与空值 19 11.5多列子查询 20 十二、 关联子查询 21 12.1语法 21 12.2执行过程 21 12.3 exists 21 12.4 exists执行过程 21 ...

    数据库实验报告 SQL查询 ,子查询组合

    (2)使用In、比较符和Exists操作符进行嵌套查询操作。 (3)分组查询,包括分组条件表达、选择组条件表达的方法。 (4)集合查询。 (5)使用视图创建语句建视图,通过视图查询数据 (6)带子查询的修改和删除 ...

    mysql exists与not exists实例详解

    mysql exists与not exists...也就是要得到类似以下语句的效果(not in 效果不完全等同于 not exists , 如果子查询中出现空记录, 则整个查询语句不会返回数据) SELECT a.* FROM tableA a WHERE a.column1 not in

    数据库作业8:SQL练习5 – SELECT(嵌套查询EXISTS、集合查询、基于派生表的查询)

    4.带有EXISTS谓词的子查询 EXISTS谓词代表存在量词, 带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。 若内层查询结果非空,则外层的WHERE子句返回真值;若内层查询结果为空,...

Global site tag (gtag.js) - Google Analytics