13 笛卡尔积(CARTESIAN)--优化主题系列

来源:互联网 发布:深圳虹云网络 编辑:程序博客网 时间:2024/06/04 17:40

提问笛卡尔积平时工作遇到的多吗??什么情况下会发生笛卡尔积??

笛卡尔积JOIN性能一定很差吗??有没有性能很好的时候??

JOIN条件的时候会不会发生笛卡尔积??

 

笛卡尔积(CartesianJoin)

 

当一个SQL中两个表无关联条件,或者关联条件可以被忽略的时候就会发生笛卡尔积。遇到这种情况要仔细分析SQL是否符合需求,是不是SQL写错了。在有些情况下,如果CBO预估两个表返回的行数很少(通常小于10),那么也可能发生笛卡尔积。遇到这样的情况:

1.如果SQL跑得很快,并且两个表返回的真实行数确实很少,那么走笛卡尔积可能是最优化

  的,这个时候我们不用管。只要是SQL跑得快我们都不用管。

2.统计信息不准确导致CBO错误估算,从而引发笛卡尔积连接。这时要更新统计信息。

3.CBO计算返回行数错误,导致笛卡尔积。CBO计算返回行数错误经常发生,因为CBO是基

  于一些数学公式计算的,出错很正常。这个时候我们可以用HINT更正执行计划。

 

在做SQL优化的时候,要注意MERGEJOIN CARTESIAN关键字,一旦发现有笛卡尔积仔细分析到底是哪些原因引发的

 

小例子如下:

explain plan for SELECT b.agmt_id,

              b.corp_org,

              b.cur_cd,

              b.businesstype,

              c.object_no,

              c.guaranty_crsum,

              row_number() over(PARTITION BY b.agmt_id, b.corp_org, c.object_no ORDER BYb.agmt_id, b.corp_org, c.object_no) row_no

          FROMb_m_business_contract         b,

              dwf.f_contract_relative       c,

              dwf.f_agt_guaranty_relative_h r,

              dwf.f_agt_guaranty_info_h     g

         WHEREb.corp_org = c.corp_org

           ANDb.agmt_id = c.contract_seqno

           ANDc.object_type = 'GuarantyContract'

           ANDr.start_dt <= DATE'2012-12-12'

           ANDr.end_dt > DATE'2012-12-12'

           ANDc.contract_seqno = r.object_no

           ANDc.object_no = r.guaranty_no

           ANDc.corp_org = r.corp_org

           ANDr.object_type = 'BusinessContract'

           ANDr.agmt_id = g.agmt_id

           ANDr.corp_org = g.corp_org

           ANDg.start_dt <= DATE'2012-12-12'

           ANDg.end_dt > DATE'2012-12-12'

         ANDg.guarantytype = '121212'


看到这个执行计划,第一眼就知道是B_M_BUSINESS_CONTRACT表出问题了,请看我分析步骤:

1.ID=6这步是全表扫描,并且没过滤条件(因为没有*)

2.CBO认为它只返回1行。你自己想想,全表扫描返回1行,并且无过滤条件,这个可能吗,

  难道表里面真的就只有1行数据?这不符合常识,那么显然是它统计信息有问题。

3.根据前面提到的知识,如果返回的行数真的很少,那么走笛卡尔积它反而更快。

 

这些因素最终导致了走笛卡尔积。

当然了,你也可以手工的select count(*) from B_M_BUSINESS_CONTRACT;

查看返回数据,当你看到返回几千上万条,那么你也知道它统计信息有问题。

 

我们假设这个表1000条数据这个很可能吧??

是不是总的结果放大了1000倍??后果是什么??

是不是导致了NL的被驱动表很无辜的被扫描了 1000次??

所以这个SQL比之前很可能慢1000

如果真的返回1条结果那么执行计划就是对的因为没有进行数据的放大

看到MERGEJOIN CARTESIAN关键字要看关键字下面的返回记录数

ID=5 这个是笛卡尔积的关键字也就是ID=6count一把看返回行数是不是1

超过1行基本上就是错误的只需要管理他最近的即可

无论是NL还是笛卡尔积都直管离它最近的即可

要防止I/O爆炸式增长

SQL优化的核心思想是什么??减少I/O


原创粉丝点击