3

背景

最近我公司从 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 的任何情况都会导致失败。

4

2 回答 2

1

这里有一个小的编程错误,但看起来也有一个优化器错误。将 aLEFT 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                
于 2014-11-12T20:32:43.413 回答
1

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

于 2014-11-12T20:02:20.853 回答