我注意到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(*)?
COUNT(*)
SELECT *
SELECT COUNT(*)
的解释计划SELECT * ...:
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 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
优化器不应选择在第二个查询中使用EMP.DEPT_ID上的索引,因为它可以具有NULL值。这就是导致它从结果中排除一行的原因。
我目前唯一能想到的非错误解释是,您已经以某种方式在DISABLE RELY模式下创建了约束,以便优化程序认为该字段不能包含NULL。在这种情况下,给定约束中不正确的信息,使用索引将是正确的。但是,似乎RELY选项不适用于NOT NULL约束,因此我不认为这可能是问题所在。但是,请仔细查看表上的所有约束。
除此之外,关于完全外部联接的错误结果,Oracle网站上存在许多令人惊讶的错误。您可能会打中其中之一。在许多情况下,解决方法是禁用“本地”完全外部联接,您可以使用以下语句在当前会话中执行此操作:
alter session set "_optimizer_native_full_outer_join"=off;