半联结&反联结!
半联结是在两个数据集(表)之间的联结,其中第一个数据集中的数据行在决定是否返回时会根据在另一个数据集中出现或不出现至少一个相匹配的数据行来确定。“不出先”匹配行——这是半联结的一种特殊形式,称为反联结。
标准的内联结与半联结之间最主要的区别在于在半联结中,第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 语句中多次使用相同的表. 可以看到, ...
随机推荐
- null与undefined
null是一个表示"无"的对象,转为数值时为0:undefined是一个表示"无"的原始值,转为数值时为NaN. undefined和null在if语句中,都会 ...
- Appium 并发多进程基于 Pytest框架
前言: 之前通过重写unittest的初始化方法加入设备参数进行并发,实现了基于unittest的appium多设备并发,但是考虑到unittest的框架实在过于简陋,也不方便后期的Jenkins的持 ...
- tensorflow模型持久化保存和加载
模型文件的保存 tensorflow将模型保持到本地会生成4个文件: meta文件:保存了网络的图结构,包含变量.op.集合等信息 ckpt文件: 二进制文件,保存了网络中所有权重.偏置等变量数值,分 ...
- HDOJ 1061 Rightmost Digit
找出数学规律 原题: Rightmost Digit Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Ja ...
- 代理模式及Spring AOP (一)
一.代理模式 在不更改源码的前提下,加入新功能,通常需要用到代理设计模式. 代理设计模式分类: 静态代理 动态代理 jdk动态代理 cglib动态代理 其中spring AOP的底层用的是动态代理.其 ...
- pta 奇数值结点链表&&单链表结点删除
本题要求实现两个函数,分别将读入的数据存储为单链表.将链表中奇数值的结点重新组成一个新的链表.链表结点定义如下: struct ListNode { int data; ListNode *next; ...
- hdu5228
bc41第一题 德州扑克的背景,给出五张牌,问最少要换多少张牌能凑齐同花顺 其实很水,数据量很小,随便暴力,越粗暴越好,然后我wa了一发因为没有看全题目,10\11\12\13\1也是一组同花顺``` ...
- JQuery禁止回车提交表单
//禁止回车键提交表单——动态绑定 $(function(){ $("input").on('keypress', //所有input标签回车无效,当然,可以根据需求自定义 fu ...
- WebSocket(二)-WebSocket、Socket、TCP、HTTP区别
原文地址:Socket 与 WebSocket 1. 概述 WebSocket 是为了满足基于 Web 的日益增长的实时通信需求而产生的.在传统的 Web 中,要实现实时通信,通用的方式是采用 HTT ...
- repo学习笔记
1. 遍历所有的git仓库,并在每个仓库执行-c所指定的命令(被执行的命令不限于git命令,而是任何被系统支持的命令,比如:ls . pwd .cp 等 . $ repo forall -c &quo ...