半连接
http://book.51cto.com/art/201312/422461.htm
1.2.4.4 半连接
《基于Oracle的SQL优化》第1章Oracle里的优化器,本章会详细介绍与Oracle数据库里优化器相关的基础知识,目的是希望通过这一章的介绍,让大家对Oracle数据库里的优化器有一个全局、概要性的认识,打好基础,为阅读后续章节扫清障碍。本节为大家介绍半连接。
1.2.4.4 半连接
半连接(Semi Join)是一种特殊的连接类型,与反连接一样,Oracle数据库里也没有相关的关键字可以在SQL文本中专门表示半连接,所以这里也把它单独拿出来说明。
为了方便说明半连接的含义,这里我们用"t1.x semi= t2.y"来表示表T1和表T2做半连接,且T1是驱动表,T2是被驱动表,半连接条件为t1.x=t2.y。这里"t1.x semi= t2.y"的含义是只要在表T2中找到一条记录满足t1.x=t2.y,则马上停止搜索表T2,并直接返回表T1中满足条件t1.x=t2.y的记录。也就是说,表T2中满足半连接条件t1.x=t2.y的记录即使有多条,表T1中也只会返回第一条满足条件的记录。所以半连接和普通的内连接不同,半连接实际上会去重。
内连接(join)与半连接(semi join)的区别就是有没有根据匹配字段连接重复字段的数据(其作用几乎相同)
举一个例子:
如下表的 dept的 id=1 有两个重复的id 部门编号字段
emp(雇员表)
id dept_id name
1 1 z s
_____________________________________________
dept(部门表)
id dept_name
1 xx
1 oo
当部门表中有重复的部门 编号 时,
join 时 会 将两条重复数据都匹配连接,得到结果:
zs 1, xx部门 --继续匹配连接
zx 1, oo部门
半连接, 在匹配了第一条数据后就停止匹配,不向下继续匹配, 只生成一条数据
zs 1, xx部 --停止继续向下匹配连接
优点:
半连接 semi-join :只取出表中匹配的数据,从而减少内存的占用
操作
如左半连接 left-semi-join
select * from emp e left semi join dept d on e.dept_id=d.id;
相当于
select * from emp where id in (select id from dept);
当做子查询展开时,Oracle经常会把那些外部where条件为EXISTS、IN或= ANY的子查询转换为对应的半连接(关于子查询展开,会在第4章的"4.2 子查询展开"中详细说明,这里不再赘述)。
我们来看如下3个范例SQL(这里还是以"1.2.4.1.1 内连接"中的测试表T1和T2为例来说明)。
范例SQL 32:
- select * from t1
- where col2 in (select col2 from t2);
范例SQL 33:
- select * from t1
- where col2 = any (select col2 from t2);
范例SQL 34:
- select * from t1
- where exists (select 1 from t2 where col2 = t1.col2);
上述范例SQL 32、33、34实际上是等价的,我们现在来执行它们:
- SQL> set autotrace on
- SQL> select * from t1
- 2 where col2 in (select col2 from t2);
- SQL> select * from t1
- 2 where col2 = any (select col2 from t2);
注意,上述三个范例SQL的执行结果是一样的,而且它们的执行计划的显示内容中均有关键字"HASH JOIN SEMI",其中的关键字"SEMI"就说明Oracle在执行这三个范例SQL时确实是在用半连接,即Oracle实际上是将它们转换成了如下的等价半连接形式:
- select t1.* from t1,t2
- where t1.col2 semi= t2.col2