转自http://www.2cto.com/database/201310/251176.html

对于in和exists、not in和not exists还是有很多的人有疑惑,更有甚者禁用not in,所有的地方都要用not exists,它真的高效吗?

【实验1 in和exists原理及性能比较】

准备数据

create table test1 as select * from dba_objects where rownum <=1000;

create table test2 as select * from dba_objects;

exec dbms_stats.gather_table_stats(user,'test1');

exec dbms_stats.gather_table_stats(user,'test2');

set autotrace traceonly

in 查询

select * from test1 t1 where t1.object_id in (select t2.object_id from test2 t2);

执行计划

----------------------------------------------------------
Plan hash value: 3819917785

----------------------------------------------------------------------------
| Id | Operation        | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT   |     | 1000 | 90000 | 307 (1)  | 00:00:04 |
|* 1 | HASH JOIN SEMI    |     | 1000 | 90000 | 307 (1)  | 00:00:04 |
| 2 | TABLE ACCESS FULL  | TEST1 | 1000 | 85000 | 6 (0)   | 00:00:01 |
| 3 | TABLE ACCESS FULL  | TEST2 | 73119 | 357K| 301 (1)  | 00:00:04 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
98 consistent gets
0 physical reads
0 redo size
50936 bytes sent via SQL*Net to client
1226 bytes received via SQL*Net from client
68 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1000 rows processed

exists 查询

select * from test1 t1 where exists(select 1 from test2 t2 where t1.object_id=t2.object_id);

执行计划
----------------------------------------------------------
Plan hash value: 3819917785

----------------------------------------------------------------------------
| Id | Operation        | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT   |     | 1000 | 90000 | 307 (1)  | 00:00:04 |
|* 1 | HASH JOIN SEMI    |     | 1000 | 90000 | 307 (1)  | 00:00:04 |
| 2 | TABLE ACCESS FULL  | TEST1 | 1000 | 85000 | 6 (0)   | 00:00:01 |
| 3 | TABLE ACCESS FULL  | TEST2 | 73119 | 357K| 301 (1)  | 00:00:04 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
98 consistent gets
0 physical reads
0 redo size
50936 bytes sent via SQL*Net to client
1226 bytes received via SQL*Net from client
68 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1000 rows processed

结论:

在oracle 11g中,in和exists 其实是一样的,原理就是两张表做HASH JOIN SEMI。也可以通过10053事件看到两条sql语句最终转换成同一条sql。

【实验2 not in和not exists原理及性能比较】

not exists 比 not in 效率高的例子(按照转载文章实验,执行计划和文章不符,结果是效率相同,可能是由于本人使用版本11g高于原文章缘故)

保持test1 和 test2 数据不变,分别是 1000、70000+

select count(*) from test1 where object_id not in (select object_id from test2);

select count(*) from test1 t1 where not exists(select 1 from test2 t2 where t1.object_id=t2.object_id);

执行计划相同,此处就省略了。

执行计划相同;效率一样

not in 比 not exists 效率高的例子(依然和转载文章结果不符,结果还是效率相同,后来我用hint改变了not in的执行计划才能显示出not in的优势)

准备数据

创建表t1和t2,结构和test1、test2一样,但是t1数据量为5条,t2数据量为20W+

select count(*) from t1 where object_id not in (select /*+ no_unnest */ object_id from t2);

--注意:如果不用hint来改变执行计划,两个语句仍然是一样的执行计划;

执行计划
----------------------------------------------------------
Plan hash value: 59119136

----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 755 (1)| 00:00:10 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | FILTER | | | | | |
| 3 | TABLE ACCESS FULL| T1 | 5 | 15 | 3 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T2 | 2 | 10 | 301 (1)| 00:00:04 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter( NOT EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "T2" "T2"
WHERE LNNVL("OBJECT_ID"<>:B1)))
4 - filter(LNNVL("OBJECT_ID"<>:B1))

统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
23 consistent gets
0 physical reads
0 redo size
522 bytes sent via SQL*Net to client
500 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

select count(*) from t1 where not exists (select 1 from t2 where t1.object_id=t2.object_id);

执行计划
----------------------------------------------------------
Plan hash value: 1513027705

----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 2376 (1)| 00:00:29 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | HASH JOIN ANTI | | 1 | 8 | 2376 (1)| 00:00:29 |
| 3 | TABLE ACCESS FULL| T1 | 5 | 15 | 3 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T2 | 584K| 2856K| 2371 (1)| 00:00:29 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
8599 consistent gets
0 physical reads
0 redo size
522 bytes sent via SQL*Net to client
500 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

结论

在11g版本中,数据量如我制造类似情况下,in和exists,not in和not exists的执行计划已经基本一致了,更倾向于使用HASH JOIN,但是当外表非常小,内表非常大的情况下,通过hint改变执行计划,filter的性能可以更优于HASH JOIN,也说明了not in不一定性能比not exists 差。

【转】oracle in和exists、not in和not exists原理和性能探究的更多相关文章

  1. SQL里的EXISTS与in、not exists与not in

    系统要求进行SQL优化,对效率比较低的SQL进行优化,使其运行效率更高,其中要求对SQL中的部分in/not in修改为exists/not exists 修改方法如下: in的SQL语句 SELEC ...

  2. 为什么 EXISTS(NOT EXIST) 与 JOIN(LEFT JOIN) 的性能会比 IN(NOT IN) 好

    前言 网络上有大量的资料提及将 IN 改成 JOIN 或者 exist,然后修改完成之后确实变快了,可是为什么会变快呢?IN.EXIST.JOIN 在 MySQL 中的实现逻辑如何理解呢?本文也是比较 ...

  3. Oracle数据库重做日志及归档日志的工作原理说明

    Oracle数据库重做日志及归档日志的工作原理: lgwr进程将redo log buffer中的重做数据写入到redo log中,此时的redo log分组,每当一个redo log group写满 ...

  4. Oracle 分区表管理之组合分区(分区索引失效与性能比较)

    整体结构如下: Oracle  分区表管理之组合分区(分区索引失效与性能比较) 虽然老早就使用了分区表,终于有时间写有关分区表的内容:不是所有的场景数据量变大需要用到分区表,一般单表数据超过2g可以考 ...

  5. oracle 11g亿级复杂SQL优化一例(数量级性能提升)

    自从16年之后,因为工作原因,项目中就没有再使用oracle了,最近最近支持一个项目,又要开始负责这块事情了.最近在跑性能测试,配置全部调好之后,不少sql还存在性能低下的问题,主要涉及执行计划的不合 ...

  6. 《Oracle DBA工作笔记:运维、数据迁移与性能调优》 PDF 下载

    一:下载途径 二:本书图样 三:本书目录 第1篇 数据库运维篇第1章 数据库安装配置1.1 安装前的准备 11.2 安装数据库软件 51.2.1 方法1:OUI安装 61.2.2 方法2:静默安装 8 ...

  7. 谨慎使用 FileInfo.Exists 实例方法,而是使用 File.Exists 静态方法替代

    如果你在代码中使用了 FileInfo.Exists 实例方法来判断一个文件是否存在,也许会发现此方法可能错误地判断来一个文件是否真的存在.这是一个坑. 本文将介绍坑的原因,并提供填坑的办法. 本文内 ...

  8. 【转】Oracle Freelist和HWM原理及性能优化

    文章转自:http://www.wzsky.net/html/Program/DataBase/74799.html 近期来,FreeList的重要作用逐渐为Oracle DBA所认识,网上也出现一些 ...

  9. NOT IN、NOT EXISTS的相关子查询改用LEFT JOIN--sql2000性能优化

    参考文章:SQL SERVER性能优化综述(很好的总结,不要错过哦) 数据库:系统数据库 子查询的用法 子查询是一个 SELECT 查询,它嵌套在 SELECT.INSERT.UPDATE.DELET ...

随机推荐

  1. IOS setValue forKey

    NSObjiect *obj:[obj setValue:value forKey:@"cpname"]复制代码的时候都会出现这个异常this class is not key v ...

  2. JQery判断checkbox是否被选三种方式

    方法一:if ($("#checkbox-id").get(0).checked) {    // do something} 方法二:if($('#checkbox-id').i ...

  3. Dapper学习笔记(2)-链接引用

    在研究Dapper源码时发现Dapper NET45类库中的SqlMapper.cs文件前面有个蓝色的箭头图标,发现在Dapper NET45文件夹下根本不存在SqlMapper.cs文件,其文件属性 ...

  4. 破解Outlook数据文件密码/PST访问密码

    不少人会经常用outlook,邮件多的时候可能不定期导出一个PST文件,为安全起见,给PST文件设置访问密码,可是时间长了,难免忘记,怎么办呢?不用担心,你自己就可以解决,无论是Outlook97.O ...

  5. C#在数据层过滤属性中的主键

    C#使用泛型+反射做为数据层时,一个很都头疼的问题,如何让C#属性在程序里识别出哪个属性是主键,在拼接SQL时,不能把主键拼接到SQL语句里. 这个需要自定义一个属性.新建一个类文件,命名为Prosp ...

  6. Qt 获取本机ip地址  【转自 CSDN jpchen609

    QString str; QHostInfo info=QHostInfo::fromName(QHostInfo::localHostName()); //定义一个HostInfo的对象然后对这个对 ...

  7. 2015-2016最火的Android开源项目--github开源项目集锦(不看你就out了)

    标签: Android开发开源项目最火Android项目github 2015-2016最火的Android开源项目 本文整理与集结了近期github上使用最广泛最火热与最流行的开源项目,想要充电与提 ...

  8. 关于XML文档

    很多人觉得XML很简单,但我想说其实一点也不简单,特别是在当今被各种web文档充斥的世界里有必要对XML进行一定程度的研究.下面的几篇博客将对XML技术进行简短的说明.

  9. 解决ie6 fixed 定位以及抖动问题

    像你所遇到的问题一样, IE6浏览器有太多的bug让制作网页的人头疼.这篇文章介绍的是介绍的是如何解决IE6不支持position:fixed;属性的办法.如果我们需要做某个元素始终位于浏览器的底部, ...

  10. linux内核分析——扒开系统调用的三层皮(上)

    20135125陈智威 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 系统调用 ...