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