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 左外连接问题(有空表?)的主要内容,如果未能解决你的问题,请参考以下文章