`
liwenshui322
  • 浏览: 520343 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

(转)关于semi-join/anti-join的一点探讨

 
阅读更多

  原博客地址:http://space.itpub.net/15480802/viewspace-703260

 

create table dept (deptno number(5), dname varchar2(20));
create table emp (deptno number(5), name varchar2(20));
insert into dept values(1,'IT');
insert into dept values(2,'HR');
insert into dept values(3,'Marketplace');
insert into emp values(1,'justin1');
insert into emp values(1,'justin2');
insert into emp values(2,'justin3');
commit;

Semi-join
通常出现在使用了exists或in的sql中,所谓semi-join即在两表关联时,当第二个表中存在一个或多个匹配记录时,返回第一个表的记录;
与普通join的区别在于semi-join时,第一个表里的记录最多只返回一次;

例1
现在要查询出职员不为空的部门
普通的表连接会返回重复值
SQL> select d.deptno,d.dname from dept d, emp e where e.deptno = d.deptno;
 
DEPTNO DNAME
------ --------------------
     1 IT
     1 IT
     2 HR
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     3 |   114 |     7  (15)| 00:00:01 |
|*  1 |  HASH JOIN         |      |     3 |   114 |     7  (15)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPT |     3 |    75 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |     3 |    39 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------
而使用semi-join时候,不会返回重复记录
SQL> select d.deptno,d.dname from dept d where d.deptno in (select e.deptno from emp e);
 
DEPTNO DNAME
------ --------------------
     1 IT
     2 HR
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     2 |    76 |     7  (15)| 00:00:01 |
|*  1 |  HASH JOIN SEMI    |      |     2 |    76 |     7  (15)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPT |     3 |    75 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |     3 |    39 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

 

Anti-join
而anti-join则与semi-join相反,即当在第二张表没有发现匹配记录时,才会返回第一张表里的记录;
当使用not exists/not in的时候会用到,两者在处理null值的时候会有所区别


何时选择anti-join
1 使用not in且相应列有not null约束
2 not exists,不保证每次都用到anti-join
当无法选择anti-join时,oracle常会采用filter替代

例2
查询职员为空的部门
普通sql
SQL> select d.deptno,d.dname from dept d
  2  minus
  3  select d.deptno,d.dname from dept d where d.deptno in (select e.deptno from emp e);
 
DEPTNO DNAME
------ --------------------
     3 Marketplace
-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |     3 |   189 |    12  (75)| 00:00:01 |
|   1 |  MINUS               |      |       |       |            |          |
|   2 |   SORT UNIQUE        |      |     3 |    75 |     4  (25)| 00:00:01 |
|   3 |    TABLE ACCESS FULL | DEPT |     3 |    75 |     3   (0)| 00:00:01 |
|   4 |   SORT UNIQUE        |      |     3 |   114 |     8  (25)| 00:00:01 |
|*  5 |    HASH JOIN         |      |     3 |   114 |     7  (15)| 00:00:01 |
|   6 |     TABLE ACCESS FULL| EMP  |     3 |    39 |     3   (0)| 00:00:01 |
|   7 |     TABLE ACCESS FULL| DEPT |     3 |    75 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------

使用anti join
SQL> select d.deptno,d.dname from dept d
  2  where d.deptno not in (select deptno from emp);
 
DEPTNO DNAME
------ --------------------
     3 Marketplace
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     3 |   114 |     7  (15)| 00:00:01 |
|*  1 |  HASH JOIN ANTI NA |      |     3 |   114 |     7  (15)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPT |     3 |    75 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |     3 |    39 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

注:倘若subquery返回一条null值,则整个not in都变为false,即不返回任何值
If the subquery of a NOT IN clause returns at least one row with a null value, the entire NOT IN clause evaluates to false for all rows
SQL> select d.deptno,d.dname from dept d where d.deptno not in (select deptno from emp);

    DEPTNO DNAME
---------- --------------------
         3 Marketplace

SQL> insert into emp values(null,'NULL');

1 row created.

SQL> commit;

Commit complete.

SQL> select d.deptno,d.dname from dept d where d.deptno not in (select deptno from emp);

no rows selected

 

而换成not exists时候,hash join anti na变成了hash join anti

select d.deptno,d.dname from dept d where not exists (select deptno from emp where emp.deptno = d.deptno);
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     3 |   114 |     7  (15)| 00:00:01 |
|*  1 |  HASH JOIN ANTI    |      |     3 |   114 |     7  (15)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| DEPT |     3 |    75 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |     3 |    39 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------
Not exists与not in的区别在于not exists不受null值影响


注意
Oracle在解析sql时候会尽可能的把子查询转换为表连接
Oracle在以下情况不会使用semi-join
1、    使用distinct或者union
2、    Exists/in子查询中使用了or

Hash_sj/merge_sj/nl_sj都是关于semi-join的一些hint

分享到:
评论
1 楼 u011165335 2018-06-03  
distinct不影响使用半连接

相关推荐

    Oracle SQL Hints

    - USE_SEMI:指示使用半连接。 - USE_ANTI:指示使用反连接。 概要数据提示:提供额外的统计信息或优化器行为的指令。 - OPTIMIZER_FEATURES_ENABLE:固定优化器使用的特性集到指定的版本。 - OPT_PARAM:强制改变...

    oracle joins

    本文将深入探讨半连接(Semi-Join)和反连接(Anti-Join),这两种特殊类型的连接能有效提高特定查询的性能。 首先,半连接是一种返回第一张表中与第二张表存在匹配项的行的连接方式。与传统的内连接不同,半连接...

    Oracle SQL 优化与调优技术详解-附录:SQL提示.pdf

    - **ANTIJOIN**、**SEMIJOIN**:控制反连接和半连接的转换。 - **COALESCE_SQ**、**NO_COALESCE_SQ**:是否合并子查询。 - **ELIMINATE_JOIN**、**NO_ELIMINATE_JOIN**:是否消除连接操作。 - **ELIMINATE_OBY**、**...

    Oracle中的半联结和反联结详解

    在Oracle数据库中,半联结(Semi-Join)和反联结(Anti-Join)是两种特殊的查询操作,它们通常用于处理两个表之间的关联,但返回的结果与传统的内联结(Inner Join)和外联结(Outer Join)有所不同。这两种操作在...

    ORACLE初始化参数详解

    - **说明**:此参数控制反连接(Anti-Join)的执行方式。反连接是一种特殊的连接类型,用于返回不符合某个条件的所有行。 - **值范围**: - `NESTED_LOOPS`:采用嵌套循环算法执行。 - `MERGE`:采用排序合并算法...

    SQL Join的一些总结(实例)

    除此之外,还有更复杂的联接类型,如自联接(self join),用于在一个表中比较行,以及半联接(semi join)和反半联接(anti join),它们在某些场景下比普通联接更为高效。 在实际应用中,理解并熟练掌握不同类型...

    罗炳森-SQL等价改写核心思想

    半连接(SEMI JOIN)是另一种关键的SQL操作,它仅返回主表中与子表有匹配关系的数据。常见的半连接形式包括使用IN或EXISTS子查询。例如,查询部门(dept)中存在员工(emp)的部门信息,可以使用两种方式表达:IN子...

    SQL等价改写核心思想概述.pptx

    2. **半连接(SEMI JOIN)**: - 半连接只返回主表中与子表有匹配记录的数据,常用于`IN`或`EXISTS`子查询。这种连接方式可以减少数据传输量,提高效率。半连接的等价改写可以通过内连接实现,如将`IN`子查询转换为...

    SQL等价改写核心思想概述.pdf

    2. 半连接(SEMI JOIN): - 半连接只返回主表的数据,而且这些数据必须与子表有关联。它可以等价于IN或EXISTS子查询。例如,查询部门(dept)中存在员工(emp)的记录,可以使用IN或EXISTS来实现半连接。 3. 反...

    oracle数据库参数

    1. **always_anti_join** 和 **always_semi_join**:这两个参数涉及到SQL查询优化。`always_anti_join` 控制如何处理NOT IN子查询,可以选择NESTED_LOOPS(嵌套循环)、MERGE(合并)或HASH方法。`always_semi_join`...

    oracle初始化参数详解

    1. **always_anti_join** 和 **always_semi_join**:这两个参数涉及到查询优化。`always_anti_join`控制优化器如何处理NOT IN子查询,可以选择NESTED_LOOPS、MERGE或HASH方法。`always_semi_join`则影响EXISTS子查询...

    Hive编程指南+HIVE从入门到精通+Hive高级编程+Apache Oozie

    3. **Joins优化**: 理解不同类型的JOIN(Inner、Outer、Semi、Anti等),并优化JOIN操作以减少资源消耗。 4. **Hive与Spark集成**: 利用Spark的内存计算能力加速Hive查询。 5. **数据安全与权限**: 实现Hive的用户...

    MaxCompute SQL技术展望.pptx

    VALUES语句的兼容性和增强,以及SEMI JOIN、ANTI JOIN等新的连接类型,提高了查询的灵活性和性能。隐式连接和UNION DISTINCT等操作也得到了改进,以减少限制并优化执行效率。 总而言之,MaxCompute SQL的技术展望...

    关于数据处理包dplyr的函数用法总结

    - `semi_join()`仅保留左数据集中存在匹配的行。 - `anti_join()`保留左数据集中不存在匹配的行。 这些函数在处理数据集时提供了极大的灵活性,让数据操作变得简单而高效。掌握dplyr的这些基本操作,将极大提升R...

Global site tag (gtag.js) - Google Analytics