暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 19C 半联接

原创 Asher.HU 2021-02-04
691


 半连接是当在子查询数据集存在一个匹配的行,从所述第一组返回行两个数据集之间的联接

数据库在第一个匹配项时停止处理第二个数据集。因此,当第二数据集中的多个行满足子查询条件时,优化不会复制第一数据集中的行。

注意:半联接和反联接被视为联接类型,即使导致它们的SQL构造是子查询也是如此。它们是优化器用来展平子查询构造的内部算法,以便可以通过类似联接的方式对其进行解析。

 


半连接 和普通的内连接不同, 半连接实际上会去重。  


9.3.3.1当优化器考虑半连接时

当查询仅需要确定是否存在匹配项时,半联接可避免返回大量行。

对于大型数据集,此优化可以节省大量的时间,而这些嵌套的循环连接必须遍历内部查询返回的每条记录(对于外部查询的每一行),而嵌套循环联接则必须如此。优化器可以将半联接优化应用于嵌套循环联接,哈希联接和排序合并联接。

在以下情况下,优化器可以选择半联接:

  • 该语句使用IN or EXISTS子句。
  • 该语句在IN or  EXISTS子句中包含一个子查询
  • 该 IN 或 EXISTS条款不包含内部OR分支。

 

9.3.3.2半联接如何工作

半联接优化的实现方式取决于所使用的联接类型。

以下伪代码显示了嵌套循环连接的半连接:

FOR ds1_row IN ds1 LOOP
  match := false;
  FOR ds2_row IN ds2_subquery LOOP
    IF (ds1_row matches ds2_row) THEN
      match := true;
      EXIT -- stop processing second data set when a match is found
    END IF
  END LOOP
  IF (match = true) THEN 
    RETURN ds1_row
  END IF
END LOOP

在前面的伪代码中,ds1是第一个数据集,并且ds2_subquery是子查询数据集。该代码从第一个数据集获取第一行,然后循环遍历子查询数据集以查找匹配项。一旦找到匹配项,该代码将退出内部循环,然后开始处理第一个数据集中的下一行。

示例9-13使用WHERE EXISTS的半联接

以下查询使用WHERE EXISTS子句仅列出包含员工的部门:

SELECT department_id, department_name 
FROM   departments
WHERE EXISTS (SELECT 1
              FROM   employees 
              WHERE  employees.department_id = departments.department_id)

执行计划揭示了NESTED LOOPS SEMI步骤1中操作:

--------------------------------------------------------------------------------
| Id| Operation          | Name              |Rows|Bytes|Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT   |                   |    |     |    2 (100)|          |
| 1 |  NESTED LOOPS SEMI |                   | 11 | 209 |    2   (0)| 00:00:01 |
| 2 |   TABLE ACCESS FULL| DEPARTMENTS       | 27 | 432 |    2   (0)| 00:00:01 |
|*3 |   INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 44 | 132 |    0   (0)|          |
--------------------------------------------------------------------------------

对于departments组成外部循环的中的每一行,数据库获取部门ID,然后探测employees.department_id索引以查找匹配的条目。从概念上讲,索引如下所示:

10,rowid
10,rowid
10,rowid
10,rowid
30,rowid
30,rowid
30,rowid
...

如果表中的第一个条目departments是department 30,那么数据库将对索引执行范围扫描,直到找到第一个30条目为止,这时它将停止读取索引并从中返回匹配的行departments如果外部循环的下一行是department 20,则数据库将扫描索引以20查找条目,并且未找到任何匹配项,则执行外部循环的下一次迭代。数据库以这种方式进行,直到返回所有匹配的行。

示例9-14使用IN的半联接

以下查询使用IN子句仅列出包含员工的部门:

SELECT department_id, department_name
FROM   departments
WHERE  department_id IN 
       (SELECT department_id 
        FROM   employees); 

执行计划揭示了NESTED LOOPS SEMI步骤1中操作:

--------------------------------------------------------------------------------
| Id| Operation          | Name              |Rows|Bytes|Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT   |                   |    |     |    2 (100)|          |
| 1 |  NESTED LOOPS SEMI |                   | 11 | 209 |    2   (0)| 00:00:01 |
| 2 |   TABLE ACCESS FULL| DEPARTMENTS       | 27 | 432 |    2   (0)| 00:00:01 |
|*3 |   INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 44 | 132 |    0   (0)|          |
--------------------------------------------------------------------------------

该计划与示例9-13中的计划相同

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论