半联结&反联结!
半联结是在两个数据集(表)之间的联结,其中第一个数据集中的数据行在决定是否返回时会根据在另一个数据集中出现或不出现至少一个相匹配的数据行来确定。“不出先”匹配行——这是半联结的一种特殊形式,称为反联结。
标准的内联结与半联结之间最主要的区别在于在半联结中,第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 语句中多次使用相同的表. 可以看到, ...
随机推荐
- JavaScript权威指南——跳转语句
前言:JavaScript中有一类语句叫做跳转语句.从名称就可以看出,它使得JavaScript的执行可以从一个位置跳转到另一个位置. return语句让解释器跳出循环体的执行,并提供本次调用的返回值 ...
- python perlin noise
python 利用 noise 生成纹理. # -*- coding: utf-8 -*- """ Created on Mon Apr 23 20:04:41 2018 ...
- 【01_292】Nim Game
Nim Game Total Accepted: 25342 Total Submissions: 50672 Difficulty: Easy You are playing the followi ...
- [Algorithm] How to find all the subsets of an n-element set T?
There are two direction for us to solve this problem. (1) Recursion Recursive step: T[0] conbines wi ...
- (MyEclipse) MyEclipse完美破解方法(图)
http://photo.blog.sina.com.cn/list/blogpic.php?pid=53358777td408badc4071&bid=533587770101dd03&am ...
- (3)什么是函数(函数的定义、形参、实参、默认形参、可变长函数args|kwargs)
什么是函数 函数是指将一组语句的集合通过一个名字(函数名)封装起来,想要执行这个函数,只需调用其函数名即可 1.减少重复代码 2.使程序变的可扩展 3.使程序变得易维护 定义函数的语法 形参 主要的作 ...
- CTF之当铺密码
当铺密码即:汉字的笔画有几笔出头,则代表数字几 例如:由=1 王=6 大=5
- day02 大型互联网架构演变历程笔记 和nigix和keepalived
PS:1.单个进程内,有多个线程,可以共享进程的内存空间2. 进程和进程之间通信比较麻烦, 会涉及 序列化和反序列化 PS :以一个交易网站看网站是如何变大的,网站的发展!!!! PS:随着请求的增加 ...
- stenciljs 学习十一 pwa 支持
stenciljs 对于pwa 的支持是自动注入的,我们只需要简单的配置,stenciljs使用workbox 配置 默认配置 { skipWaiting: true, clientsClaim: t ...
- 看懂Class文件的装载流程
Class文件的加载过程 ClassLoader的工作模式 类的热加载 1 Class文件的装载流程 只有被java虚拟机装载的Class类型才能在程序中使用(注意装载和加载的区别) 1.1 类装载的 ...