13 笛卡尔积(CARTESIAN)--优化主题系列
提问笛卡尔积平时工作遇到的多吗??什么情况下会发生笛卡尔积??
笛卡尔积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