ORACLE 左外连接问题(有空表?)

Posted

技术标签:

【中文标题】ORACLE 左外连接问题(有空表?)【英文标题】:ORACLE left outer join issue (with empty table?) 【发布时间】:2014-10-08 16:50:46 【问题描述】:

我想知道为什么这个查询:

select l.objectID LEFT_CODE, r.object_code RIGHT_CODE
from OGGETTO_ORGANIZZATIVO l left outer join
    ANAG_OGGETTO_ORGANIZZATIVO r on l.objectID = r.objectID
WHERE r.objectID IS NULL;

返回一些行,而这个其他查询

select l.objectID LEFT_CODE
from OGGETTO_ORGANIZZATIVO l left outer join
    ANAG_OGGETTO_ORGANIZZATIVO r on l.objectID = r.objectID
WHERE r.objectID IS NULL;

不返回任何内容。 我的问题是在右表中插入左表中存在但不在右表中的所有行;目前右表是空的。

看来,如果我没有在 select 子句中引用正确的字段,oracle 将不会管理外连接。

提前致谢。 保罗

[更新] 第一次查询

select l.codice_oggetto_SAP
from oggetto_organizzativo l left outer join
  ANAG_OGGETTO_ORGANIZZATIVO_SAP r
    ON l.codice_oggetto_sap = r.codice_oggetto_SAP
WHERE r.codice_oggetto_sap is null

执行计划

第二次查询

select l.codice_oggetto_SAP, r.codice_oggetto_SAP
from oggetto_organizzativo l left outer join
  ANAG_OGGETTO_ORGANIZZATIVO_SAP r
    ON l.codice_oggetto_sap = r.codice_oggetto_SAP
WHERE r.codice_oggetto_sap is null

执行计划

第一个执行计划语句(NULL IS NOT NULL) 在我看来很好奇...

[第二次更新] @toddlermenot,

但为什么这有效???:

CREATE TABLE LEFT_TBL
   (    "OBJECTID" VARCHAR2(20 BYTE)  ) ;

CREATE TABLE RIGHT_TBL
   (    "OBJECTID" VARCHAR2(20 BYTE)  ) ;

INSERT ALL
  INTO LEFT_TBL (OBJECTID) VALUES ('AAA')
  INTO LEFT_TBL (OBJECTID) VALUES ('BBB')
  INTO LEFT_TBL (OBJECTID) VALUES ('CCC')  
SELECT * from DUAL;

SELECT l.objectID
FROM LEFT_TBL l LEFT OUTER JOIN RIGHT_TBL r
  ON L.OBJECTID = r.OBJECTID
WHERE r.OBJECTID IS NULL;

看这个执行计划

Plan hash value: 2059691840

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     3 |    72 |     5   (0)| 00:00:01 |
|*  1 |  HASH JOIN ANTI    |           |     3 |    72 |     5   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| LEFT_TBL  |     3 |    36 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| RIGHT_TBL |     1 |    12 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("L"."OBJECTID"="R"."OBJECTID")

Note
-----
   - dynamic sampling used for this statement (level=2)

可能是和索引问题?

【问题讨论】:

您描述的行为将是一个错误。你能在 SQL Fiddle 上重现它吗? Oracle 的哪个版本? 但是直觉.. Oracle 不会这样做blunder.. 至少在 Oracle 11g 中它可以正常工作.. Fiddle Reference 有趣。这可能是由 CBO 走不应该走的捷径引起的错误吗?能否请您发布两个查询的执行计划?。 @joe:Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production 【参考方案1】:

您发布的解释计划可能与实际的执行计划不同。 区别在于 解释计划 正是优化器 (CBO) 认为 在实际执行查询期间将遵循的可能会偏离真正的执行计划.

话虽如此,如果您的解释计划是可信的,那么这绝对是一个优化器错误,正如我在评论中假设的那样。 出于某种原因,在您的第一个查询中,CBO 采用 incorrect 快捷方式并忽略了 LEFT OUTER 连接(根本不访问正确的表)并使用奇怪的 NULL is NOT NULL 谓词作为最终过滤器这总是FALSE,这意味着你的最终结果集总是空的。

要解决此问题,您可能需要向 Oracle 支持提出请求并修补您的数据库以修复此错误。

编辑:如果两个表的统计信息都已过期,请收集两个表的统计信息并尝试重新运行查询。收集统计数据后,CBO 可能会采取正确的计划。然而,统计数据过时仍然不是 CBO 选择不正确执行计划的借口。您可能希望在向 Oracle 支持提出请求后执行此操作,以便在他们处理此错误行为时仍然可以重现此错误行为。

【讨论】:

@PaoloUrsini:您似乎正在使用 SQL Developer 工具,并且选项卡在屏幕截图中显示它是“解释计划”。获取实际执行计划的方法有多种:一种常见的方法是使用 dbms_xplan.display_cursor -> docs.oracle.com/database/121/TGSQL/tgsql_interp.htm#TGSQL94854。 首先,非常感谢!我用类似于给我问题的第二种情况更新了帖子,但这确实有效!!!也许真的是一个统计问题:-(我会让我的 DBA 有兴趣向 Oracle 支持寻求帮助。再次感谢。 不客气。我必须同意你的观点,这个问题是特定于你的情况的,并且不能用一组新的表来重现,比如 Maheswaran Ravisankar 的 SQL Fiddle。这就是为什么我建议您仅在 Oracle 支持人员工作后才收集统计数据。【参考方案2】:

错误 10269193 - 外部联接和 CASE 表达式优化(CASE 不需要存在)或 LIKE 运算符(文档 ID 10269193.8)的错误结果

产品(组件)

Oracle 服务器 (Rdbms)

据信受影响的版本范围

版本 >= 11.2 但低于 12.1

症状:

相关:

可能发生内部错误 (ORA-600) 错误的结果 ORA-600 [kkfdjoi:kkfdnpart_DIM1]

【讨论】:

以上是关于ORACLE 左外连接问题(有空表?)的主要内容,如果未能解决你的问题,请参考以下文章

oracle 左外连接如果右表中有重复数据如何处理?

如何在 Oracle 中转换“旧版”左外连接语句?

将涉及多个表的左外连接从 Informix 重写为 Oracle

使用左外连接时 Oracle 分区修剪不起作用

Oracle左外连接问题

左外连接与右外连接区别?