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

Oracle 19C 外部联接

原创 Asher.HU 2021-02-04
846


一个外部联接返回满足连接条件,并且还从一个表的行对于没有从另一表中的行满足条件的所有行因此,外部联接的结果集是内部联接的超集

在ANSI语法中,该OUTER JOIN子句指定外部联接。FROM子句中,左表显示在OUTER JOIN关键字的左侧,右表显示在这些关键字的右侧。左表也称为外部表,右表也称为内部表例如,在以下语句中,employees表是左侧表或外部表:

SELECT employee_id, last_name, first_name
FROM   employees LEFT OUTER JOIN departments
ON     (employees.department_id=departments.departments_id);

外部联接要求将外部联接的表作为驱动表。在前面的示例中,employees是驱动表,并且departments是被驱动表。



9.3.2.1嵌套循环外部联接

数据库使用此操作在两个表之间循环进行外部联接。外部联接返回外部(保留)表行,即使内部(可选)表中没有相应的行也是如此。

在标准的嵌套循环中,优化器根据成本选择表的顺序(驱动表和从动表)。但是,在嵌套循环外部联接中,联接条件确定表的顺序。数据库使用外部行保留表驱动到内部表。

在以下情况下,优化器使用嵌套循环联接来处理外部联接:

  • 可以从外表驱动到内表。
  • 数据量不足以使嵌套循环方法高效。

对于嵌套循环外部联接的示例,可以在示例9-9中添加USE_NL提示,以指示优化器使用嵌套循环。例如:

SELECT /*+ USE_NL(c o) */ cust_last_name,
       SUM(NVL2(o.customer_id,0,1)) "Count"
FROM   customers c, orders o
WHERE  c.credit_limit > 1000
AND    c.customer_id = o.customer_id(+)
GROUP BY cust_last_name;


9.3.2.2哈希联接外部联接

当数据量足够大以提高哈希联接的效率,或者无法从外部表驱动到内部表时,优化器将使用哈希联接来处理外部联接。

成本决定表格的顺序。外部表(包括保留的行)可以用于构建哈希表,也可以用于探测哈希表。

示例9-9哈希联接外部联接

此示例显示了典型的哈希联接外部联接查询及其执行计划。在此示例中,将查询所有信用额度大于1000的客户。需要外部联接,以便查询捕获没有订单的客户。

  • 外面的桌子是customers
  • 内部表是orders
  • 联接保留customers行,包括中没有对应行的行orders

您可以使用NOT EXISTS子查询返回行。但是,因为查询的是表中的所有行,所以哈希联接的性能更好(除非NOT EXISTS不嵌套子查询)。

SELECT cust_last_name, SUM(NVL2(o.customer_id,0,1)) "Count"
FROM   customers c, orders o
WHERE  c.credit_limit > 1000
AND    c.customer_id = o.customer_id(+)
GROUP BY cust_last_name;

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|  0 | SELECT STATEMENT    |           |       |       |     7 (100)|          |
|  1 |  HASH GROUP BY      |           |   168 |  3192 |     7  (29)| 00:00:01 |
|* 2 |   HASH JOIN OUTER   |           |   318 |  6042 |     6  (17)| 00:00:01 |
|* 3 |    TABLE ACCESS FULL| CUSTOMERS |   260 |  3900 |     3   (0)| 00:00:01 |
|* 4 |    TABLE ACCESS FULL| ORDERS    |   105 |   420 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("C"."CUSTOMER_ID"="O"."CUSTOMER_ID")
 
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
   3 - filter("C"."CREDIT_LIMIT">1000)
   4 - filter("O"."CUSTOMER_ID">0)

该查询查找满足各种条件的客户。当外部联接NULL在内部表中找不到任何对应的行时,它将返回内部表的列以及外部(保留的)表行。此操作将查找customers没有任何orders行的所有行。

在这种情况下,外部联接条件如下:

customers.customer_id = orders.customer_id(+)

此条件的组件表示以下内容:

示例9-10外部联接到多表视图

在此示例中,外部联接是多表视图优化器无法像普通联接一样进入视图或推送谓词,因此它会构建视图的整个行集。

SELECT c.cust_last_name, sum(revenue)
FROM   customers c, v_orders o
WHERE  c.credit_limit > 2000
AND    o.customer_id(+) = c.customer_id
GROUP BY c.cust_last_name;

----------------------------------------------------------------------------
| Id  | Operation              |  Name        | Rows  | Bytes | Cost (%CPU)|
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |              |   144 |  4608 |    16  (32)|
|   1 |  HASH GROUP BY         |              |   144 |  4608 |    16  (32)|
|*  2 |   HASH JOIN OUTER      |              |   663 | 21216 |    15  (27)|
|*  3 |    TABLE ACCESS FULL   | CUSTOMERS    |   195 |  2925 |     6  (17)|
|   4 |    VIEW                | V_ORDERS     |   665 | 11305 |            |
|   5 |     HASH GROUP BY      |              |   665 | 15960 |     9  (34)|
|*  6 |      HASH JOIN         |              |   665 | 15960 |     8  (25)|
|*  7 |       TABLE ACCESS FULL| ORDERS       |   105 |   840 |     4  (25)|
|   8 |       TABLE ACCESS FULL| ORDER_ITEMS  |   665 | 10640 |     4  (25)|
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("O"."CUSTOMER_ID"(+)="C"."CUSTOMER_ID")
   3 - filter("C"."CREDIT_LIMIT">2000)
   6 - access("O"."ORDER_ID"="L"."ORDER_ID")
   7 - filter("O"."CUSTOMER_ID">0)

视图定义如下:

CREATE OR REPLACE view v_orders AS
SELECT l.product_id, SUM(l.quantity*unit_price) revenue, 
       o.order_id, o.customer_id
FROM   orders o, order_items l
WHERE  o.order_id = l.order_id
GROUP BY l.product_id, o.order_id, o.customer_id;

 

9.3.2.3排序合并外部联接

当外部联接无法从外部(保留)表驱动到内部(可选)表时,它不能使用哈希联接或嵌套循环联接。

在这种情况下,它使用排序合并外部联接。

在以下情况下,优化器对外部联接使用排序合并:

  • 嵌套循环联接效率很低。由于数据量大,嵌套循环联接可能效率低下。
  • 优化程序发现,由于其他操作需要排序,因此在散列连接上使用排序合并会更便宜。

 

9.3.2.4完全外部联接

一个完全外部连接是左和右外的组合连接。

除了内部联接之外,两个表中由于内部联接而未返回的行也将保留并扩展为null。换句话说,完全外部联接将表联接在一起,但显示联接表中没有对应行的行。

示例9-11完全外部联接

以下查询检索所有部门以及每个部门中的所有员工,但还包括:

  • 任何没有部门的员工
  • 任何没有员工的部门
SELECT d.department_id, e.employee_id
FROM   employees e FULL OUTER JOIN departments d
ON     e.department_id = d.department_id
ORDER BY d.department_id;

该语句产生以下输出:

DEPARTMENT_ID EMPLOYEE_ID
------------- -----------
           10         200
           20         201
           20         202
           30         114
           30         115
           30         116
...
          270
          280
                      178
                      207

125 rows selected.

示例9-12完整外部联接的执行计划

从Oracle Database 11 g开始,Oracle数据库会自动使用基于哈希联接的本机执行方法来尽可能执行完全外部联接当数据库使用new方法执行完全外部联接时,查询的执行计划将包含HASH JOIN FULL OUTER示例9-11中的查询使用以下执行计划:

--------------------------------------------------------------------------------
| Id| Operation               | Name       |Rows |Bytes |Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT        |            | 122 | 4758 |   6  (34)| 00:0 0:01 |
| 1 |  SORT ORDER BY          |            | 122 | 4758 |   6  (34)| 00:0 0:01 |
| 2 |   VIEW                  | VW_FOJ_0   | 122 | 4758 |   5  (20)| 00:0 0:01 |
|*3 |    HASH JOIN FULL OUTER |            | 122 | 1342 |   5  (20)| 00:0 0:01 |
| 4 |     INDEX FAST FULL SCAN| DEPT_ID_PK |  27 |  108 |   2   (0)| 00:0 0:01 |
| 5 |     TABLE ACCESS FULL   | EMPLOYEES  | 107 |  749 |   2   (0)| 00:0 0:01 |
--------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")

HASH JOIN FULL OUTER包含在前面的计划(步骤3)中,指示查询使用哈希完整外部联接执行方法。通常,当两个表之间的完全外部联接条件为等联接时,可以使用哈希完全外部联接执行方法,并且Oracle数据库会自动使用它。

要指示优化器考虑使用哈希完全外部联接执行方法,请应用NATIVE_FULL_OUTER_JOIN提示。要指示优化器不要考虑使用哈希完全外部联接执行方法,请应用NO_NATIVE_FULL_OUTER_JOIN提示。所述NO_NATIVE_FULL_OUTER_JOIN提示指示优化接合每个指定表时排除天然执行方法。相反,完整的外部联接将作为左外部联接和反联接的并集执行。

 

9.3.2.5外部联接左侧的多个表

Oracle Database 12c中,外部联接表的左侧可能存在多个表。

此增强功能使Oracle数据库可以合并包含多个表的视图,该视图显示在外部联接的左侧。Oracle Database 12c之前的版本中,诸如以下的查询无效,并且会触发ORA-01417错误消息:

SELECT t1.d, t3.c
FROM   t1, t2, t3
WHERE  t1.z = t2.z 
AND    t1.x = t3.x (+) 
AND    t2.y = t3.y (+);

Oracle Database 12c开始,上述查询有效。

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

评论