暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 查询转换-远程数据库

askTom 2018-03-20
298

问题描述

嗨,

我有一个查询,从远程数据库获取数据,这个数据不是我所期望的 (更少的数据或没有数据)。我确实尝试了解导致问题的原因,并注意到在远程数据库上运行时查询正在转换。
根据我所看到的,这是一个错误,或者是我对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子句的左表上指定的谓词作为联接的一部分进行评估。实际上,您可以在执行计划下面的注释部分中看到这一点,因为这些谓词显示为访问谓词,而不是过滤器谓词。

让我们以您的原始示例为例:
使用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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论