sql - Oracle Exadata - LEFT OUTER JOIN 在连接条件下使用 AND 时表现得像 INNER

标签 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 的任何情况都会导致失败。

最佳答案

这里有一个小的编程错误,但看起来也有一个优化器错误。将 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;

这两个查询在 Oracle 11.2.0.3、EE、Solaris 上返回此结果:

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

关于sql - Oracle Exadata - LEFT OUTER JOIN 在连接条件下使用 AND 时表现得像 INNER,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26893723/

相关文章:

sql - 将一个数字分成相等的范围并使用 select for oracle 数据库作为行返回?

php - 无法输出多维数组

sql - MySQL日期查询问题

mysql - 根据外部表过滤结果

c++ - ODBC 写入 blob 示例 Oracle C++

java - 如何在Oracle中回滚/超时 “select for update”锁?

sql - 子选择(而不是数字常量)恶化优化

sql - COUNT() 基于表中列的影响

sql - 更新 Postgres 的竞争条件(读取已提交)