半联结&反联结!
半联结是在两个数据集(表)之间的联结,其中第一个数据集中的数据行在决定是否返回时会根据在另一个数据集中出现或不出现至少一个相匹配的数据行来确定。“不出先”匹配行——这是半联结的一种特殊形式,称为反联结。
标准的内联结与半联结之间最主要的区别在于在半联结中,第1个数据集中的每一条记录至返回一次,而不管在第二个数据集中有几条匹配的数据。这个定义表明这个查询的实际处理过程可以通过在找到第1个匹配以后马上停止第二个查询来进行优化。
从本质上来说,这就是半联结:可以通过在查询2执行完成之前停止处理该查询来进行优化。这种联结技术在oracle基于成本的优化器中查询中又包含在IN或EXISTS句中的子查询时是一种可选方案。
1、半联结
/*+ SEMIJOIN */ 进行半联结(优化器选用使用哪种类型)。
/*+ NO_SEMIJOIN */ 显示的意味着不行进半联结。
- SQL> select * from emp order by job;
- EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
- ---------- ---------- --------- ---------- -------------- ---------- ---------- ----------
- 7788 SCOTT ANALYST 7566 19-4月 -87 3000 20
- 7902 FORD ANALYST 7566 03-12月-81 3000 20
- 7934 MILLER CLERK 7782 23-1月 -82 1300 10
- 7900 JAMES CLERK 7698 03-12月-81 950 30
- 7369 SMITH CLERK 7902 17-12月-80 800 20
- 7876 ADAMS CLERK 7788 23-5月 -87 1100 20
- 7698 BLAKE MANAGER 7839 01-5月 -81 2850 30
- 7566 JONES MANAGER 7839 02-4月 -81 2975 20
- 7782 CLARK MANAGER 7839 09-6月 -81 2450 10
- 7839 KING PRESIDENT 17-11月-81 5000 10
- 7844 TURNER SALESMAN 7698 08-9月 -81 1500 0 30
- EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
- ---------- ---------- --------- ---------- -------------- ---------- ---------- ----------
- 7654 MARTIN SALESMAN 7698 28-9月 -81 1250 1400 30
- 7521 WARD SALESMAN 7698 22-2月 -81 1250 500 30
- 7499 ALLEN SALESMAN 7698 20-2月 -81 1600 300 30
- 已选择14行。
分析上面的数据可以看出JOB='SALESMAN'的DEPTNO有4条重复的记录,值都是30。那么如下的子查询返回的记录就有重复的记录!
- select e.ename, e.job, e.sal
- from emp e
- where e.deptno in (select d.deptno from emp d where d.job = 'SALESMAN');
- select e.ename, e.job, e.sal
- from emp e
- where exists (select null
- from emp d
- where e.deptno = d.deptno
- and d.job = 'SALESMAN');
看执行计划:
- SQL> select e.ename, e.job, e.sal
- 2 from emp e
- 3 where e.deptno in (select d.deptno from emp d where d.job = 'SALESMAN');
- ENAME JOB SAL
- ---------- --------- ----------
- JAMES CLERK 950
- TURNER SALESMAN 1500
- BLAKE MANAGER 2850
- MARTIN SALESMAN 1250
- WARD SALESMAN 1250
- ALLEN SALESMAN 1600
- 已选择6行。
- 执行计划
- ----------------------------------------------------------
- Plan hash value: 977554918
- ---------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- ---------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 14 | 448 | 7 (15)| 00:00:01 |
- |* 1 | HASH JOIN SEMI | | 14 | 448 | 7 (15)| 00:00:01 |
- | 2 | TABLE ACCESS FULL| EMP | 14 | 294 | 3 (0)| 00:00:01 |
- |* 3 | TABLE ACCESS FULL| EMP | 3 | 33 | 3 (0)| 00:00:01 |
- ---------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - access("E"."DEPTNO"="D"."DEPTNO")
- 3 - filter("D"."JOB"='SALESMAN')
- SQL>
- SQL>
- SQL> select e.ename, e.job, e.sal
- 2 from emp e
- 3 where exists (select null
- 4 from emp d
- 5 where e.deptno = d.deptno
- 6 and d.job = 'SALESMAN');
- ENAME JOB SAL
- ---------- --------- ----------
- JAMES CLERK 950
- TURNER SALESMAN 1500
- BLAKE MANAGER 2850
- MARTIN SALESMAN 1250
- WARD SALESMAN 1250
- ALLEN SALESMAN 1600
- 已选择6行。
- 执行计划
- ----------------------------------------------------------
- Plan hash value: 977554918
- ---------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- ---------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 14 | 448 | 7 (15)| 00:00:01 |
- |* 1 | HASH JOIN SEMI | | 14 | 448 | 7 (15)| 00:00:01 |
- | 2 | TABLE ACCESS FULL| EMP | 14 | 294 | 3 (0)| 00:00:01 |
- |* 3 | TABLE ACCESS FULL| EMP | 3 | 33 | 3 (0)| 00:00:01 |
- ---------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - access("E"."DEPTNO"="D"."DEPTNO")
- 3 - filter("D"."JOB"='SALESMAN')
使用IN和EXISTS的执行计划是一致的,这一点就为了消除长期以来人们认为的使用EXISTS查询与使用IN查询的处理方法很不相同这种观点。注意执行计划中的“SEMI”就代表使用了半联结!
- SQL> select e.ename, e.job, e.sal
- 2 from emp e
- 3 where e.deptno in (select /*+ no_semijoin */
- 4 d.deptno
- 5 from emp d
- 6 where d.job = 'SALESMAN');
- ENAME JOB SAL
- ---------- --------- ----------
- ALLEN SALESMAN 1600
- WARD SALESMAN 1250
- MARTIN SALESMAN 1250
- BLAKE MANAGER 2850
- TURNER SALESMAN 1500
- JAMES CLERK 950
- 已选择6行。
- 执行计划
- ----------------------------------------------------------
- Plan hash value: 2389097100
- ---------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- ---------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 9 | 306 | 8 (25)| 00:00:01 |
- |* 1 | HASH JOIN | | 9 | 306 | 8 (25)| 00:00:01 |
- | 2 | VIEW | VW_NSO_1 | 2 | 26 | 4 (25)| 00:00:01 |
- | 3 | HASH UNIQUE | | 2 | 22 | 4 (25)| 00:00:01 |
- |* 4 | TABLE ACCESS FULL| EMP | 3 | 33 | 3 (0)| 00:00:01 |
- | 5 | TABLE ACCESS FULL | EMP | 14 | 294 | 3 (0)| 00:00:01 |
- ---------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - access("E"."DEPTNO"="DEPTNO")
- 4 - filter("D"."JOB"='SALESMAN')
- SQL>
- SQL>
- SQL> select e.ename, e.job, e.sal
- 2 from emp e
- 3 where exists (select /*+ no_semijoin */
- 4 null
- 5 from emp d
- 6 where e.deptno = d.deptno
- 7 and d.job = 'SALESMAN');
- ENAME JOB SAL
- ---------- --------- ----------
- ALLEN SALESMAN 1600
- WARD SALESMAN 1250
- MARTIN SALESMAN 1250
- BLAKE MANAGER 2850
- TURNER SALESMAN 1500
- JAMES CLERK 950
- 已选择6行。
- 执行计划
- ----------------------------------------------------------
- Plan hash value: 2561671593
- ---------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- ---------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 5 | 105 | 12 (0)| 00:00:01 |
- |* 1 | FILTER | | | | | |
- | 2 | TABLE ACCESS FULL| EMP | 14 | 294 | 3 (0)| 00:00:01 |
- |* 3 | TABLE ACCESS FULL| EMP | 1 | 11 | 3 (0)| 00:00:01 |
- ---------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - filter( EXISTS (SELECT 0 FROM "EMP" "D" WHERE
- "D"."JOB"='SALESMAN' AND "D"."DEPTNO"=:B1))
- 3 - filter("D"."JOB"='SALESMAN' AND "D"."DEPTNO"=:B1)
使用NO_SEMIJOIN提示关闭了优化器使用半联结的能力。可以看见使用使用IN和EXISTS的执行计划还不一样了。
2、反联结
/*+ ANTIJOIN */ 进行反联接(优化器决定具体类型)
/*+ USE_ANTI */ ANTIJOIN提示的旧版本
- SQL> select e.ename, e.job, e.sal
- 2 from emp e
- 3 where e.deptno not in
- 4 (select d.deptno from emp d where d.job = 'PRESIDENT');
- ENAME JOB SAL
- ---------- --------- ----------
- JAMES CLERK 950
- TURNER SALESMAN 1500
- BLAKE MANAGER 2850
- MARTIN SALESMAN 1250
- WARD SALESMAN 1250
- ALLEN SALESMAN 1600
- FORD ANALYST 3000
- ADAMS CLERK 1100
- SCOTT ANALYST 3000
- JONES MANAGER 2975
- SMITH CLERK 800
- 已选择11行。
- 执行计划
- ----------------------------------------------------------
- Plan hash value: 4002838083
- ---------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- ---------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 5 | 160 | 7 (15)| 00:00:01 |
- |* 1 | HASH JOIN ANTI NA | | 5 | 160 | 7 (15)| 00:00:01 |
- | 2 | TABLE ACCESS FULL| EMP | 14 | 294 | 3 (0)| 00:00:01 |
- |* 3 | TABLE ACCESS FULL| EMP | 3 | 33 | 3 (0)| 00:00:01 |
- ---------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - access("E"."DEPTNO"="D"."DEPTNO")
- 3 - filter("D"."JOB"='PRESIDENT')
- SQL>
- SQL>
- SQL> select e.ename, e.job, e.sal
- 2 from emp e
- 3 where not exists (select null
- 4 from emp d
- 5 where e.deptno = d.deptno
- 6 and d.job = 'PRESIDENT');
- ENAME JOB SAL
- ---------- --------- ----------
- JAMES CLERK 950
- TURNER SALESMAN 1500
- BLAKE MANAGER 2850
- MARTIN SALESMAN 1250
- WARD SALESMAN 1250
- ALLEN SALESMAN 1600
- FORD ANALYST 3000
- ADAMS CLERK 1100
- SCOTT ANALYST 3000
- JONES MANAGER 2975
- SMITH CLERK 800
- 已选择11行。
- 执行计划
- ----------------------------------------------------------
- Plan hash value: 3353202012
- ---------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- ---------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 5 | 160 | 7 (15)| 00:00:01 |
- |* 1 | HASH JOIN ANTI | | 5 | 160 | 7 (15)| 00:00:01 |
- | 2 | TABLE ACCESS FULL| EMP | 14 | 294 | 3 (0)| 00:00:01 |
- |* 3 | TABLE ACCESS FULL| EMP | 3 | 33 | 3 (0)| 00:00:01 |
- ---------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - access("E"."DEPTNO"="D"."DEPTNO")
- 3 - filter("D"."JOB"='PRESIDENT')
执行计划中的“ANTI” 就是反联结的意思,而在NOT IN的执行计划中还有“NA” 表示考虑NULL值的意思。
转载:http://blog.csdn.net/zq9017197/article/details/8439353
半联结&反联结!的更多相关文章
- 11 半联结 & 反联结
半联结 和 反联结是 oracle 优化器能够选择用来在获取信息时应用的两个密切相关的联结方法(实际上是联结方法的选项) 半联结 IN 的半联结 select /* using in */ depar ...
- 读书笔记--SQL必知必会13--创建高级联结
13.1 使用表别名 SQL可以对列名.计算字段和表名起别名. 缩短SQL语句 允许在一条SELECT语句中多次使用相同的表. 注意:表别名只在查询执行中使用,不返回到客户端. MariaDB [sq ...
- SQL学习之高级联结(自联结、自然联结、外联接)
create table Customers( Id ,), Company ) null, Name ) null ) insert into Customers values('Fun4All', ...
- SQL 必知必会·笔记<11>创建高级联结
1. 使用表别名 SQL 除了可以对列名和计算字段使用别名,还允许给表名起别名.这样 做有两个主要理由: 缩短SQL 语句: 允许在一条SELECT 语句中多次使用相同的表. 使用表别名示例: SEL ...
- SQL 必知必会·笔记<10>联结表
可伸缩(scale) 能够适应不断增加的工作量而不失败.设计良好的数据库或应用程序 称为可伸缩性好(scale well). 联结(JOIN) 联结(JOIN)是一种机制,用来在一条SELECT 语句 ...
- MySQL(七)联结表
一.联结表基础知识 1.关系表 把信息分解成多个表,一类数据一个表,各表通过某些常用值(即关系设计中的关系(relational))互相关联: 2.外键(foreign key):外键为某个表中的一列 ...
- MySQL自学笔记_联结(join)
1. 背景及原因 关系型数据库的一个基本原则是将不同细分数据放在单独的表中存储.这样做的好处是: 1).避免重复数据的出现 2).方便数据更新 3).避免创建重复数据时出错 例子: 有供应商信息和产 ...
- 12.创建高级联结---SQL
一.使用表别名 SQL除了可以对列名和计算字段使用别名,还允许给表名起别名.这样做有两个主要理由: 缩短SQL语句: 允许在一条SELECT语句中多次使用相同的表. SELECT cust_name, ...
- mysql必知必会-创建高级联结
使用表别名 使用别名引用被检索的表列 别名除了用于列名和计算字段外,SQL还允许给表名起别名.这样做 有两个主要理由: 缩短SQL语句: 允许在单条 SELECT 语句中多次使用相同的表. 可以看到, ...
随机推荐
- 【微信小程序推广营销】教你微信小程序SEO优化,让你的小程序快人一步抢占先机
今年一月份上线的小程序,经过近一年的沉淀发酵,现在也进入了快速发展期. 在未来肯定会有越来越多的小程序诞生,小程序多了就需要搜索,那么如何让自己的小程序在众多的小程序中脱颖而出,这就需要小程序SEO优 ...
- ubuntu18.04 server配置静态ip (转载)
原文地址: https://blog.csdn.net/mossan/article/details/80381679 最新发布的ubuntu18.04 server,启用了新的网络工具netplan ...
- php中弱语言类型的底层实现
PHP是弱语言类型,主要分为三类: 1.标量类型:integer.string.float.boolean 2.复合类型:array.object 3.特殊类型:resource.null php是通 ...
- PS如何批量处理图片
喜爱摄影的朋友可能都有这样的体会,相机里面存了大量的图片,一般都是2048×1536或者更大像素的照片,每张都有1M以上,如果设置的清晰度高,则照片就更大,这样的图片是无法上传到博客中的(博客要求每张 ...
- python海龟绘图
最近学了python,看了几本书之后,才明白python的强大,python是一种解释型的语言,即每写一行程序就执行一行. 而且在科学计算方面,处理的能力特别的方便. 比如python中的字典dict ...
- iOS7,iOS8和iOS9的区别
iOS7,iOS8和iOS9的区别:iOS7.0 1.iOS 7是iOS面世以来在用户界面上做出改变最大的一个操作系统.iOS 7抛弃了以往的拟物化设计,而采用了扁平化设计. 苹果在重新思考 iOS ...
- python 判断 txt 编码方式
import chardet f = open('/path/file.txt',r) data = f.read() print(chardet.detect(data)
- day8 python学习 集合 深浅拷贝
1.内存地址: 字符串在20位以内,没有空格,没有特殊字符的情况下,同样的字符串内存地址是一样的 2.元组中:在只有一个值的时在后边加逗号和没有逗号的区别 t1=(1) 不加逗号这个值是什么类型就打印 ...
- stenciljs 学习十一 pwa 支持
stenciljs 对于pwa 的支持是自动注入的,我们只需要简单的配置,stenciljs使用workbox 配置 默认配置 { skipWaiting: true, clientsClaim: t ...
- UltraEdit常用设置及快捷键
= 关闭自动加载上次文件的方法,操作方法如下:首先,要打开UltraEdit,然后点击经[高级]-[配置],找到[文件处理]-[加载],把[重新载入先前在启动时打开的文件]勾去掉,并确定就可以了. 附 ...