Oracle Exadata - 在连接条件下使用AND时,LENER OUTER JOIN的作用类似于INNER

时间:2014-11-12 18:15:10

标签: sql oracle exadata

背景

最近我公司从Oracle 11g升级到Exadata。所有生产对象和数据都已成功迁移到新系统,并验证为系统之间的1:1匹配。在我们的新系统完成第一套每日ETL流程后,我们发现我们的报告表明显小于预期。经过进一步调查,我们发现添加到LEFT OUTER连接的批次ID导致了他们在11g上完美运行的问题。

问题

为什么以下查询将被视为11g上的LEFT OUTER JOIN,而是Exadata上的INNER JOIN?

SELECT 
    *
FROM DIM_CALL CALLS
LEFT OUTER JOIN FACT_ACTVY_MNGMT ACTVY_MNGMT
    ON ACTVY_MNGMT.CALL_KEY = CALLS.CALL_KEY
    AND ACTVY_MNGMT.BATCH_ID = 20141112
LEFT OUTER JOIN DIM_ACTVY ACTVY
    ON ACTVY.ACTVY_KEY = ACTVY_MNGMT.ACTVY_KEY
    AND ACTVY_MNGMT.BATCH_ID = 20141112

更新

看来在ETL过程中使用的查询中有一个拼写错误,或者原始开发人员忽略了这种情况。如果查看最后一次加入,您会注意到该连接位于ACTVY_KEY和BATCH_ID上。问题是它引用的BATCH_ID来自ACTVY_MNGMT表。数据库本质上将其视为WHERE子句,因此任何CALL_KEY为NULL的情况都会导致失败。

2 个答案:

答案 0 :(得分:1)

看来在ETL过程中使用的查询中有一个拼写错误,或者原始开发人员忽略了这种情况。如果查看最后一次加入,您会注意到该连接位于ACTVY_KEY和BATCH_ID上。问题是它引用的BATCH_ID来自ACTVY_MNGMT表。数据库本质上将其视为WHERE子句,因此任何CALL_KEY为NULL的情况都会导致失败。

答案 1 :(得分:1)

这里有一个小的编程错误,但它看起来也有一个优化器错误。可以将LEFT JOIN视为先前的,而不仅仅是之前的。将重复的谓词添加到不同的LEFT JOIN不应该有任何区别。

我的猜测是有一个优化器或解析器错误,带有一些奇特的Exadata功能,例如智能扫描。

此代码与您的问题类似。但是,在Solaris上的11.2.0.3 EE上,为我重现错误。在Exadata上,它甚至可能无法为您重现错误。这只是为了表明您所描述的问题是一个错误。像你一样,避免这个错误通常是最好的方法。但您可能还希望使用Oracle支持创建服务请求以查看问题。同样的错误可能会以不太明显的方式影响其他代码。

with table1 as (select '1' a, '1' b from dual),
     table2 as (select '1' a, '2' b from dual),
     table3 as (select '1' a, '2' b from dual)
select *
from table1
left join table2
    on table1.a = table2.a
    and table2.b = 3
left join table3
    on table2.a = table3.a;

with table1 as (select '1' a, '1' b from dual),
     table2 as (select '1' a, '2' b from dual),
     table3 as (select '1' a, '2' b from dual)
select *
from table1
left join table2
    on table1.a = table2.a
    and table2.b = 3
left join table3
    on table2.a = table3.a
    --This predicate is logically redundant but does *not* change results.
    and table2.b = 3;

两个查询都在Solaris上的Oracle 11.2.0.3,EE上返回此结果:

A   B   A   B   A   B
-   -   -   -   -   -
1   1