<![endif]--> <![endif]-->

发现公司同事很喜欢用exists 和in 做子查询关联,我觉得很有必要研究下

两者的区别,供参考和备忘

/* (这段信息来自网络begin )对于in 的使用,就相当于对inner table 执行一个带distinct 的子查询,然后将得到的结果集再和outer table 进行外连接,连接方式和索引使用任然同于普通两表的连接(这段信息来自网络end )*/

对于网络的这段描述,我给予了测试,测试表为 liomuser.staff ,和liomuser.department ,这两张表都是小表,数量在1 万左右。

-- 例如:

select *

from liomuser.staff

where department_id in ( select department_id from liomuser.department);

-- 可以转换为

select a.*

from liomuser.staff a,

( select distinct department_id from liomuser.department) b

where a.department_id = b.department_id;

执行计划分别如下:

( 1 ) select *

from liomuser.staff

where department_id in ( select department_id from liomuser.department);

( 2 ) select a.*

from liomuser.staff a,

( select distinct department_id from liomuser.department) b

where a.department_id = b.department_id;

我选择的是两个小表,从数据上看采用外连接的方式除了一致性读要稍微小一点,两者执行计划和统计信息几乎一样。

测试结果显示对于小表网络上给出的描述是正确的

但是以我的经验,in 的方式应该比外连接性能要差很多,按照上面的测试,两者似乎是一样的执行路径,是不是应为表数据量少的缘故呢?

我决定采用两张大表做测试,cust_order 和order_detail 这两张表的数据量都在一千万以上。

首先测试in ,语句如下:

select a.*

from liomuser.cust_order a

where order_id in ( select order_id from liomuser.order_detail b);

执行计划如下:

测试2 外连接,语句如下:

select a.*

from liomuser.cust_order a,

( select distinct order_id from liomuser.order_detail) b

where a.order_id = .order_id ;

执行计划如下:

对着两个大表的in 和外连接的对比可以看出,采用外连接的执行计划明显优于in 的方式,采用in方式则表连接采用nested loop 方式,而外连接采用了HASH JOIN ,

并且in 方式的CPUcost 要比外连接大1/3, 这样看来,对于小表,或者说inner table 是小表的查询,in 和外连接都差不多,但是对于大表,特别是inner table 数据量巨大的时候,采用外连接要好很多。

由此看出,in 并不完全等同于与inner table 做distinct 外连接,但是外连接要比in 有效率得多。

下面讨论下 EXIST

实际上exists 等同于先对outer table 进行扫描,从中检索到每行和inner table 做循环匹配,执行计划如下:

注释:部分网上资料认为exists 对outer table 会进行全表扫描,但是在该执行计划中没有发现全表扫描,仍然走了索引。

Exists 的写法可以转换成:

declare cnt number ( 10 );

for cur in ( select a.*  from liomuser.cust_order a) loop

cnt:= 0 ;

select count ( 1 ) into cnt from liomuser.order_detail where order_id=cur.order_id;

if cnt<> 0 then

return cur;

end if ;

end loop ;

exists 与 in 的比对:

语句 1 , in

语句 2 , exsits

从执行计划上来看没有任何区别,再让我们看看执行的统计信息:

语句 1 , in

select a.*

from liomuser.cust_order a

where order_id in ( select order_id from liomuser.order_detail b)

语句 2 , exists

select a.*

from liomuser.cust_order a

where exists

( select 1 from liomuser.order_detail b where a.order_id = b.order_id)

从两种方式统计信息可以看出,采用 exists 的一致性读要比 in 要好,但是 bytessent 要比 in高,这个也从侧面验证了前面所说的 exists 相当于 loop

 

通过上面解释现在很容易明白当 inner table 数据量巨大且索引情况不好 ( 大量重复值等 ) 则不宜使用产生对 inner table 检索而导致系统开支巨大 IN 操作,建议对 innertable 过大的查询,采取 exsits ,或者外连接方式

另外: NOT IN 子句将执行个内部排序和合并 . 无论在哪种情况下 ,NOT IN 都是

最低效 ( 它对子查询中表执行了个全表遍历 ). 为了避免使用 NOT IN , 我们可以把它改写成外连接 (Outer Joins) 或 NOT EXISTS

plsql exist和in 的区别的更多相关文章

  1. PLSQL oracle32位 oracle64 安装区别及注意问题

    一.先明确几个概念: 1.PLSQL 只有32位的. 2.oracle 客户端 分别有32.64位,一般使用32位. 3.oracle 服务端 分别有32.64位,一般老的服务器使用32位,新的服务器 ...

  2. Mysql的exist与in的区别

    如果查询的两个表大小相当,那么用in和exists差别不大. 如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in:    例如:表A(小表),表B(大表)   1: s ...

  3. 常用SQL语句优化技巧

    除了建立索引之外,保持良好的SQL语句编写习惯将会降低SQL性能问题发生. ①通过变量的方式来设置参数 好:stringsql = "select * from people p where ...

  4. 总结一些php的面试题

    1.PHP语言的一大优势是跨平台,什么是跨平台?一.PHP基础: PHP的运行环境最优搭配为Apache+MySQL+PHP,此运行环境可以在不同操作系统(例如windows.Linux等)上配置,不 ...

  5. php面试题汇总四(基础篇附答案)

    1. 什么事面向对象?主要特征是什么? 面向对象是程序的一种设计方式,它利于提高程序的重用性,使程序结构更加清晰.主要特征:封装.继承.多态. 2. SESSION 与 COOKIE的区别是什么,请从 ...

  6. 邓_php面试【003】——完整版

    php面试题汇总四(基础篇附答案) 1. 什么事面向对象?主要特征是什么? 面向对象是程序的一种设计方式,它利于提高程序的重用性,使程序结构更加清晰.主要特征:封装.继承.多态. 2. SESSION ...

  7. oracle逐步学习总结之约束(基础五)

    原创作品,转自请在文章明显位置注明出处:https://www.cnblogs.com/sunshine5683/p/10167717.html oracle中的约束主要有非空约束(not null) ...

  8. 安装64位的oracle数据库, 使用自带的sqldeveloper

    个人感觉这个东西比plsql要好用, 虽然界面有点丑, 整个使用与plsql也没多大区别, 这里是他的位置C:\oracle_11g\product\11.2.0\dbhome_1\sqldevelo ...

  9. 很有用的PHP笔试题系列三

    1. 什么事面向对象?主要特征是什么? 面向对象是程序的一种设计方式,它利于提高程序的重用性,使程序结构更加清晰.主要特征:封装.继承.多态. 2. SESSION 与 COOKIE的区别是什么,请从 ...

随机推荐

  1. dorado基本事件样例

    var info = self.get("returnValue"); view.set("#labelProduct.text","产品:" ...

  2. 桶排序(BucketSort)

    1 桶排序核心思想是 根据数据规模n划分 m个相同大小的区间 (每个区间为一个桶,桶可理解为容器) 2 每个桶存储区间内的元素(区间为半开区间 例如[0,10) 或者 [200,300) ) 3 将n ...

  3. OpenJudge 2795 金银岛

    1.链接地址: http://bailian.openjudge.cn/practice/2795/ 2.题目: 总Time Limit: 3000ms Memory Limit: 65536kB D ...

  4. PHP知识分享之session && cookie

    <?php /* * @Content : session && cookie * @author : Mr.xml * @time : 2015-3-17 09:53:49 * ...

  5. HttpWebRequest中的KeepAlive

    一直不是非常理解.NET中HttpWebRequest的KeepAlive属性有何用处,看了这篇文章就清楚了! http://www.cnblogs.com/lwzz/archive/2011/08/ ...

  6. CentOS添加RPMforge软件源

    1.查看CentOS版本 cat /etc/redhat-release 2.查看系统位数 uname -i 3.下载rpm包 wget "rpm地址" CentOS 6: i68 ...

  7. Python SqlAlchemy使用方法

    1.初始化连接 from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker engine = create ...

  8. 七,WPF的元素绑定

    数据绑定是一种关系,该关系告诉WPF从一个源对象提取一些信息,并使用这些信息设置目标对象的属性,目标属性总是依赖项属性,然而,源对象可以是任何内容. 源对象是WPF元素并且源属性是依赖项属性的数据绑定 ...

  9. An error occurred while collecting items to be installed session context was:(profile=DefaultProfile... 解决方案

    遇到同样问题的小伙伴请:点击Eclipse上方工具栏中help --> Install new software... --> 看图 点击进红框的位置在打开的窗口中,将窗口右侧的Avail ...

  10. 属性观察者willSet与didSet

    在Swift中使用willSet和didSet这两个特性来监视属性的除初始化之外的属性值变化. willSet里面是新值,即属性即将要变为的值:didSet里面是旧值,即属性变化之前的值. impor ...