设为首页 收藏本站
查看: 877|回复: 0

[经验分享] 关于Oracle full outer join 的bug问题分析及处理

[复制链接]

尚未签到

发表于 2018-9-11 12:18:25 | 显示全部楼层 |阅读模式
  full (outer) join是用来全连接两个表的语法。即希望将A表和B表关联,能够得到A表中有而B表中没有的记录,或者B表中有而A表中没有的记录。
DSC0000.jpg

  如何判断是否有该记录,则通过on子句来关联。
  下面是一个例子:
  SQL> with
  2  A as(select 1 a, 2 b from dual),
  3  B as(select 2 a, 3 b from dual)
  4  select * from A full join B
  5      on A.a=B.a
  6  /
  A          B          A          B
  ---------- ---------- ---------- ----------
  1          2
  2          3
  了解了以上基本原理后,我们应该知道,理论上讲,A表和B表的在from子句中的顺序是没有关系的,也就是不影响结果。但是,实际上,却出现了这样的问题,下面是对这种情况的描述:
  --------------------------------------------------------------------------------------------

  |>  --------------------------------------------------------------------------------------------
  |  0 | SELECT STATEMENT        |                | 12791 |  349K|    82  (3)| 00:00:01 |
  |  1 |  VIEW                    |                | 12791 |  349K|    82  (3)| 00:00:01 |
  |  2 |  UNION-ALL              |                |      |      |            |          |
  |*  3 |    FILTER                |                |      |      |            |          |
  |*  4 |    HASH JOIN RIGHT OUTER|                | 12790 |  1124K|    41  (3)| 00:00:01 |
  |  5 |      TABLE ACCESS FULL  | JXC_RISHARESUM  |  1735 | 78075 |    7  (0)| 00:00:01 |
  |  6 |      TABLE ACCESS FULL  | JXC_ALLTRADEDAY | 12790 |  562K|    33  (0)| 00:00:01 |
  |*  7 |    HASH JOIN ANTI        |                |    1 |    76 |    41  (3)| 00:00:01 |
  |*  8 |    TABLE ACCESS FULL    | JXC_RISHARESUM  |    1 |    45 |    7  (0)| 00:00:01 |
  |  9 |    TABLE ACCESS FULL    | JXC_ALLTRADEDAY | 12790 |  387K|    33  (0)| 00:00:01 |
  --------------------------------------------------------------------------------------------
  从以上执行计划来看,在第四步骤,使用的是hash join rigth outer连接方式。而通过改变两表的摆放顺序,得到如下的执行计划:
  -----------------------------------------------------------------------------------------

  |>  -----------------------------------------------------------------------------------------
  |  0 | SELECT STATEMENT      |                |  1876 | 52528 |    82  (3)| 00:00:01 |
  |  1 |  VIEW                |                |  1876 | 52528 |    82  (3)| 00:00:01 |
  |  2 |  UNION-ALL          |                |      |      |            |          |
  |*  3 |    FILTER            |                |      |      |            |          |
  |*  4 |    HASH JOIN OUTER  |                |  1874 |  164K|    41  (3)| 00:00:01 |
  |  5 |      TABLE ACCESS FULL| JXC_RISHARESUM  |  1735 | 78075 |    7  (0)| 00:00:01 |
  |  6 |      TABLE ACCESS FULL| JXC_ALLTRADEDAY | 12790 |  562K|    33  (0)| 00:00:01 |
  |*  7 |    HASH JOIN ANTI    |                |    2 |  152 |    41  (3)| 00:00:01 |
  |*  8 |    TABLE ACCESS FULL | JXC_ALLTRADEDAY |    2 |    90 |    33  (0)| 00:00:01 |
  |  9 |    TABLE ACCESS FULL | JXC_RISHARESUM  |  1735 | 53785 |    7  (0)| 00:00:01 |
  -----------------------------------------------------------------------------------------
  注意,此时,执行计划中的第四个步骤,变成了:hash join outer方式。这个才是我们所期望的方式。那究竟是什么导致了这个变化呢?查看他们的谓词连接逻辑:
  hash join right outer的:
  3 - filter(NVL("T1"."C_SHARENO","T2"."C_SHARENO")='26200703200004969020')
  4 - access("T2"."D_TRADEDATE"="T1"."D_TRADEDATE"(+) AND
  "T2"."D_REGDATE"="T1"."D_REGDATE"(+) AND "T2"."C_FUNDCODE"="T1"."C_FUNDCODE"(+) AND
  "T2"."C_FUNDACCO"="T1"."C_FUNDACCO"(+))
  7 - access("T2"."C_FUNDACCO"="T1"."C_FUNDACCO" AND
  "T2"."C_FUNDCODE"="T1"."C_FUNDCODE" AND "T2"."D_REGDATE"="T1"."D_REGDATE" AND
  "T2"."D_TRADEDATE"="T1"."D_TRADEDATE")
  8 - filter(NVL("T1"."C_SHARENO",NULL)='26200703200004969020')
  hash join outer的:
  3 - filter(NVL("T1"."C_SHARENO","T2"."C_SHARENO")='26200703200004969020')
  4 - access("T2"."D_TRADEDATE"(+)="T1"."D_TRADEDATE" AND
  "T2"."D_REGDATE"(+)="T1"."D_REGDATE" AND "T2"."C_FUNDCODE"(+)="T1"."C_FUNDCODE"
  AND "T2"."C_FUNDACCO"(+)="T1"."C_FUNDACCO")
  7 - access("T2"."C_FUNDACCO"="T1"."C_FUNDACCO" AND
  "T2"."C_FUNDCODE"="T1"."C_FUNDCODE" AND "T2"."D_REGDATE"="T1"."D_REGDATE" AND
  "T2"."D_TRADEDATE"="T1"."D_TRADEDATE")
  8 - filter("T2"."C_SHARENO"='26200703200004969020')
  还是没有发现明显的区别。但是实际却导致了结果的不同。
  还原到原始的表连接顺序,然后对两表进行分析,再查看执行计划:
  SQL> call dbms_stats.gather_table_stats(user, 'JXC_ALLTRADEDAY');
  调用完成。
  SQL> call dbms_stats.gather_table_stats(user, 'JXC_RISHARESUM');
  .....
  -----------------------------------------------------------------------------------------

  |>  -----------------------------------------------------------------------------------------
  |  0 | SELECT STATEMENT      |                |  1738 | 48664 |    82  (3)| 00:00:01 |
  |  1 |  VIEW                |                |  1738 | 48664 |    82  (3)| 00:00:01 |
  |  2 |  UNION-ALL          |                |      |      |            |          |
  |*  3 |    FILTER            |                |      |      |            |          |
  |*  4 |    HASH JOIN OUTER  |                |  1735 |  191K|    41  (3)| 00:00:01 |
  |  5 |      TABLE ACCESS FULL| JXC_RISHARESUM  |  1735 | 98895 |    7  (0)| 00:00:01 |
  |  6 |      TABLE ACCESS FULL| JXC_ALLTRADEDAY | 12775 |  698K|    33  (0)| 00:00:01 |
  |*  7 |    HASH JOIN ANTI    |                |    3 |  276 |    41  (3)| 00:00:01 |
  |*  8 |    TABLE ACCESS FULL | JXC_ALLTRADEDAY |    3 |  168 |    33  (0)| 00:00:01 |
  |  9 |    TABLE ACCESS FULL | JXC_RISHARESUM  |  1735 | 62460 |    7  (0)| 00:00:01 |
  -----------------------------------------------------------------------------------------

  Predicate Information (identified by operation>  ---------------------------------------------------
  3 - filter(NVL("T1"."C_SHARENO","T2"."C_SHARENO")='26200703200004969020')
  4 - access("T2"."D_TRADEDATE"(+)="T1"."D_TRADEDATE" AND
  "T2"."D_REGDATE"(+)="T1"."D_REGDATE" AND "T2"."C_FUNDCODE"(+)="T1"."C_FUNDCODE"
  AND "T2"."C_FUNDACCO"(+)="T1"."C_FUNDACCO")
  7 - access("T2"."C_FUNDACCO"="T1"."C_FUNDACCO" AND
  "T2"."C_FUNDCODE"="T1"."C_FUNDCODE" AND "T2"."D_REGDATE"="T1"."D_REGDATE" AND
  "T2"."D_TRADEDATE"="T1"."D_TRADEDATE")
  8 - filter("T2"."C_SHARENO"='26200703200004969020')
  可发现,这时原来连接方式的错误执行计划被修正了,改为hash join outer连接。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-572010-1-1.html 上篇帖子: 查询Oracle执行的顺序 下篇帖子: Oracle的跟踪文件和警告文件
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表