问题描述
嗨,
我有一个查询,从远程数据库获取数据,这个数据不是我所期望的 (更少的数据或没有数据)。我确实尝试了解导致问题的原因,并注意到在远程数据库上运行时查询正在转换。
根据我所看到的,这是一个错误,或者是我对left outer join的误解。
因此,我将提供我的问题在左外连接以及我对查询转换的观察。
对左外连接的理解:
外部联接中驱动表上的过滤器/谓词将仅在执行联接时应用。这不会在整个驾驶台上应用。
示例:
在这里,仅在加入 “rawdata s” 时才应用条件MOD(f.nbr,2) = 0,因此我们能够从第一个表中获得所有10行。
我认为我在这里的理解很好。如果我错了,请告诉我。
现在来我遇到的问题:
下面的问题是基于我上面的理解。
我有一个查询从远程数据库中查询数据。我得到的结果不像预期的那样 (更少的行或没有行)。
主数据库 (启动sql的位置): 12.1.0.2.0
远程数据库: 10.2.0.3.0
从主数据库查询:
从远程数据库查询 :( 这是我从v $ sql得到的)
我在这里看到的问题是案例陈述。我认为应该如下所示。
这是虫子吗?
我有一个查询,从远程数据库获取数据,这个数据不是我所期望的 (更少的数据或没有数据)。我确实尝试了解导致问题的原因,并注意到在远程数据库上运行时查询正在转换。
根据我所看到的,这是一个错误,或者是我对left outer join的误解。
因此,我将提供我的问题在左外连接以及我对查询转换的观察。
对左外连接的理解:
外部联接中驱动表上的过滤器/谓词将仅在执行联接时应用。这不会在整个驾驶台上应用。
示例:
WITH rawdata AS (SELECT rownum nbr FROM dual CONNECT BY LEVEL < 11) SELECT f.nbr f_nbr,s.nbr s_nbr FROM rawdata f LEFT OUTER JOIN rawdata s ON (MOD(f.nbr, 2) = 0 AND s.nbr = f.nbr) ORDER BY 1 ASC;复制
F_NBR S_NBR 1 2 2 3 4 4 5 6 6 7 8 8 9 10 10复制
在这里,仅在加入 “rawdata s” 时才应用条件MOD(f.nbr,2) = 0,因此我们能够从第一个表中获得所有10行。
我认为我在这里的理解很好。如果我错了,请告诉我。
现在来我遇到的问题:
下面的问题是基于我上面的理解。
我有一个查询从远程数据库中查询数据。我得到的结果不像预期的那样 (更少的行或没有行)。
主数据库 (启动sql的位置): 12.1.0.2.0
远程数据库: 10.2.0.3.0
从主数据库查询:
SELECT rh.code AS cd ,rh.effecdate AS effdate FROM test_tab1@test_dbl rh LEFT JOIN test_tab2@test_dbl price ON rh.code = price.code AND rh.re_date = price.re_date AND rh.re_do = 'Y' WHERE rh.e_type IN ('CD', 'SS','AB') AND to_char(rh.effecdate, 'YYYY-MM-DD') = to_char(sysdate, 'YYYY-MM-DD') AND nvl(rh.d_type, 'XX') != 'DD' AND rh.date_delet IS NULL ORDER BY effdate, cd;复制
从远程数据库查询 :( 这是我从v $ sql得到的)
SELECT "A2"."CODE", "A2"."EFFECDATE" FROM "TEST_TAB1" "A2", "TEST_TAB2" "A1" WHERE ("A2"."E_TYPE" = 'AB' OR "A2"."E_TYPE" = 'CD' OR "A2"."E_TYPE" = 'SS') AND to_char("A2"."EFFECDATE", 'YYYY-MM-DD') = to_char(SYSDATE@ !, 'YYYY-MM-DD') AND nvl("A2"."D_TYPE", 'XX') <> 'DD' AND "A2"."DATE_DELET" IS NULL AND "A2"."RE_DATE" = "A1"."RE_DATE"(+) AND "A2"."CODE" = "A1"."CODE"(+) AND "A2"."RE_DO" = CASE WHEN ("A1"."CODE"(+) IS NOT NULL) THEN 'Y' ELSE 'Y' END ORDER BY "A2"."EFFECDATE", "A2"."CODE"复制
我在这里看到的问题是案例陈述。我认为应该如下所示。
AND "A2"."RE_DO" = CASE WHEN ("A1"."CODE"(+) IS NOT NULL) THEN 'Y' ELSE "A2"."RE_DO" END复制
这是虫子吗?
专家解答
在ANSI联接的on子句的左表上指定的谓词作为联接的一部分进行评估。实际上,您可以在执行计划下面的注释部分中看到这一点,因为这些谓词显示为访问谓词,而不是过滤器谓词。
让我们以您的原始示例为例:
如果我们查看计划下的谓词信息,我们会看到在NBR上连接S和F的左外连接的访问谓词,以及将MOD(f.nbr,2)= 0谓词转换为CASE语句,其中案例的两个分支都有0作为值。
在Oracle中,ANSI左外连接直接或通过左外连接的横向视图以Oracle的左外连接语法在内部表示。
我们使用CASE将左表上出现在左外联接的on子句中的任何单表过滤器谓词转换为伪外联接谓词。尽管它是过滤器谓词,但它出现在left outer join的ON子句中; 因此,必须将其视为外部联接谓词。对于外部联接,是否在左表的外部联接之前或外部联接评估中应用了谓词,这很重要,因为左外部联接返回左表的所有行,而不管联接谓词的评估结果是TRUE还是FALSE。
这就是我们将这种类型的过滤器谓词转换为伪外联接谓词的原因,从而迫使过滤器/伪外联接谓词与其他外联接谓词一起评估。
因此,您的示例查询实际上将被重写为
使用rawdata为
(从 <11级的双连接中选择rownum nbr)
选择f.nbr f_nbr,s.nbr s_nbr
来自rawdata f,rawdata s
其中f.nbr = s.nbr ( )
和MOD(f.nbr,2)= ((s.nbr() 不为NULL的情况)
然后0
否则为0);
如果在左外联接之前应用了过滤器谓词MOD(f.nbr,2)= 0,则它将仅产生5行,但是左外联接必须返回左表中的所有行,因此返回CASE语句。
现在让我们继续进行实际的工作负载查询。
当您通过DB链接执行左外部联接时,转换将在执行查询的数据库上发生,并且转换后的查询将通过DB链接发送,这就是为什么您在远程数据库上看到Oracle外部联接语法的原因。在您的情况下,查询是在12.1.0.2数据库上执行的。在Oracle数据库12.1.0.2中,我们重新构建了ANSI联接优化,以支持多个外部联接并提高性能。
您看到的转换后的SQL语句看起来并不意外,但这并不意味着您没有遇到错误。您是否尝试过直接在远程10g系统上运行原始SQL语句,以查看结果是否不同?
让我们以您的原始示例为例:
使用rawdata为 (从 <11级的双连接中选择rownum nbr) 选择f.nbr f_nbr,s.nbr s_nbr FROM rawdata f LEFTOUTER JOIN rawdata s ON (MOD(f.nbr, 2) = 0 AND s.nbr = f.nbr) ORDER BY 1 ASC; F_NBR S_NBR ---------- ---------- 1 2 2 3 4 4 5 6 6 7 8 8 9 10 10 10 rows selected. SQL> select * from table(dbms_xplan.display_cursor()); ----------------------------------------------------------------------------- | Id | Operation | Name | ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | 1 | TEMP TABLE TRANSFORMATION | | | 2 | LOAD AS SELECT (CURSOR DURATION MEMORY)|SYS_TEMP_0FD9D669A_57D102 | | 3 | COUNT | | | 4 | CONNECT BY WITHOUT FILTERING | | | 5 | FAST DUAL | | | 6 | SORT ORDER BY | | |* 7 | HASH JOIN OUTER | | | 8 | VIEW | | | 9 | TABLE ACCESS FULL | SYS_TEMP_0FD9D669A_57D102| | 10 | VIEW | | | 11 | TABLE ACCESS FULL | SYS_TEMP_0FD9D669A_57D102| ----------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 7 - access("S"."NBR"="F"."NBR" AND MOD("F"."NBR",2)=CASE WHEN ("S"."NBR" IS NOT NULL) THEN 0 ELSE 0 END )复制
如果我们查看计划下的谓词信息,我们会看到在NBR上连接S和F的左外连接的访问谓词,以及将MOD(f.nbr,2)= 0谓词转换为CASE语句,其中案例的两个分支都有0作为值。
在Oracle中,ANSI左外连接直接或通过左外连接的横向视图以Oracle的左外连接语法在内部表示。
我们使用CASE将左表上出现在左外联接的on子句中的任何单表过滤器谓词转换为伪外联接谓词。尽管它是过滤器谓词,但它出现在left outer join的ON子句中; 因此,必须将其视为外部联接谓词。对于外部联接,是否在左表的外部联接之前或外部联接评估中应用了谓词,这很重要,因为左外部联接返回左表的所有行,而不管联接谓词的评估结果是TRUE还是FALSE。
这就是我们将这种类型的过滤器谓词转换为伪外联接谓词的原因,从而迫使过滤器/伪外联接谓词与其他外联接谓词一起评估。
因此,您的示例查询实际上将被重写为
使用rawdata为
(从 <11级的双连接中选择rownum nbr)
选择f.nbr f_nbr,s.nbr s_nbr
来自rawdata f,rawdata s
其中f.nbr = s.nbr ( )
和MOD(f.nbr,2)= ((s.nbr() 不为NULL的情况)
然后0
否则为0);
如果在左外联接之前应用了过滤器谓词MOD(f.nbr,2)= 0,则它将仅产生5行,但是左外联接必须返回左表中的所有行,因此返回CASE语句。
现在让我们继续进行实际的工作负载查询。
当您通过DB链接执行左外部联接时,转换将在执行查询的数据库上发生,并且转换后的查询将通过DB链接发送,这就是为什么您在远程数据库上看到Oracle外部联接语法的原因。在您的情况下,查询是在12.1.0.2数据库上执行的。在Oracle数据库12.1.0.2中,我们重新构建了ANSI联接优化,以支持多个外部联接并提高性能。
您看到的转换后的SQL语句看起来并不意外,但这并不意味着您没有遇到错误。您是否尝试过直接在远程10g系统上运行原始SQL语句,以查看结果是否不同?
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。