小编典典

Oracle中完全外部联接的奇怪行为-如何解释?

sql

我注意到Oracle 11中FULL OUTER JOIN的奇怪行为。我从HR模式(尤其是EMPLOYEES和DEPARTMENTS)联接表。

例如,以下查询返回123行:

    SELECT * FROM employees e
    FULL JOIN departments d ON e.department_id = d.department_id

但是,难以理解的是-当我在select子句中放置一组特定的列时,查询将返回122行(缺少行的是缺少部门的雇员的行-左连接另外返回的行)与内部联接相比):

    SELECT first_name, last_name, department_name FROM employees e
    FULL JOIN departments d on e.department_id = d.department_id

即使我计算行数也返回122(COUNT(*))!!!到底是怎么回事?SELECT *和之间有什么区别SELECT COUNT(*)

的解释计划SELECT * ...

SELECT STATEMENT                                      122
  VIEW                 VW_FOJ_0                       122
    HASH JOIN                          FULL OUTER     122
      Access Predicates
        E.DEPARTMENT_ID = D.DEPARTMENT_ID
      TABLE ACCESS     DEPARTMENTS     FULL            27
      TABLE ACCESS     EMPLOYEES       FULL           107

和为SELECT COUNT(*) ...

SELECT STATEMENT                                             1
  SORT                                     AGGREGATE         1
    VIEW               VW_FOJ_0                            122
      HASH JOIN                            FULL OUTER      122
        Access Predicates
          E.DEPARTMENT_ID = D.DEPARTMENT_ID
        INDEX          DEPT_ID_PK          FAST FULL SCAN   27
        INDEX          EMP_DEPARTMENT_IX   FAST FULL SCAN  107

阅读 181

收藏
2021-05-16

共1个答案

小编典典

优化器不应选择在第二个查询中使用EMP.DEPT_ID上的索引,因为它可以具有NULL值。这就是导致它从结果中排除一行的原因。

我目前唯一能想到的非错​​误解释是,您已经以某种方式在DISABLE
RELY模式下创建了约束,以便优化程序认为该字段不能包含NULL。在这种情况下,给定约束中不正确的信息,使用索引将是正确的。但是,似乎RELY选项不适用于NOT
NULL约束,因此我不认为这可能是问题所在。但是,请仔细查看表上的所有约束。

除此之外,关于完全外部联接的错误结果,Oracle网站上存在许多令人惊讶的错误。您可能会打中其中之一。在许多情况下,解决方法是禁用“本地”完全外部联接,您可以使用以下语句在当前会话中执行此操作:

alter session set "_optimizer_native_full_outer_join"=off;
2021-05-16