业务场景:
一张表需要自关联4次才能出结果,表DS,其中含有两个字段COL1,COL2
原SQL,执行时间31min钟
SELECT
*
FROM DS A
LEFT JOIN DS B
ON A.COL1=B.COL2
LEFT JOIN DS C
ON B.COL1=C.COL2
LEFT JOIN DS D
ON C.COL1=D.COL2
每张表大概3亿数据
我们知道,GP数据库存储数据是依据分布键来存储数据的,分布键设置的不合理,会影响后面的SQL执行,此时我们的表分布键为COL1
由于条件限制,无法贴出执行计划,但是可以看出来此SQL关联分布键并不合理,B C D 都得进行重分布,3亿数据进行重分布那是及其耗时的。
所以我们第一阶段得限制住重分布次数
1、先膨胀数据
create temp table DS_col1 as
select * from DS
distributed by (col1)
create temp table DS_col2 as
select * from DS
distributed by (col2)
创建两张临时表,一张分布键为col1 ,另一张分布键为col2 ,首先进行关联
create temp table DS_join as
select
A.COL2 AS COL2_1,A.*,B.COL1 AS COL1_2,B.*
from
DS_col1 A
left join
DS_col2 B
on A.col1=B.col2
此时减少一次重分布
我们再将最终SQL进行一次优化
select * from
DS_join C
left join
DS_join D
on C.COL1_2=D.COL2_1
再次打开执行计划,重分布的次数减少至1次,速度已经来到了17min,可是还是很耗时。
于是我们想着DS_join D 可能有大量的无用数据,
为了验证想法将DS_join D 表进行数据筛选。
create temp table DS_join2 as
select * from DS_join D
where exists
(select 1 from DS_join C where C.COL1_2=D.COL2_1)
实事证明,DS_join D 表数据中存在着大量的无用数据,数据量急剧下降
再次关联
select * from
DS_join C
left join
DS_join2 D
on C.COL1_2=D.COL2_1
执行计划中,DS_join2 被广播出去了,重分布不存在了,速度优化至5min。