【问题标题】:Is there any better way to avoid data skew by join in Redshift?有没有更好的方法通过加入 Redshift 来避免数据倾斜?
【发布时间】:2020-02-17 10:14:30
【问题描述】:

如下查询SQL导致Redshift集群一个节点磁盘满

insert
into
  report.agg_info
  ( pd ,idate ,idate_str ,app_class ,app_superset ,aid ,pf ,is ,camp ,ua_camp_id ,country ,is_predict ,cohort_size ,new_users ,retained ,acc_re ,day_iap_rev ,iap_rev ,day_rev ,rev ) 
select
    p.pd ,
    p.idate ,
    p.idate_str ,
    p.app_class ,
    p.app_superset ,
    p.aid ,
    p.pf ,
    p.is ,
    p.camp ,
    p.ua_camp_id ,
    p.country ,
    1 as is_predict ,
    p.cohort_size ,
    p.new_users ,
    p.retained ,
    ar.acc_re ,
    p.day_iap_rev ,
    ar.iap_rev ,
    p.day_rev ,
    ar.rev
from
    tmp_predict p
join
    tmp_accumulate ar
        on p.pd = ar.pd
        and p.idate = ar.idate
        and p.aid = ar.aid
        and p.pf = ar.pf
        and p.is = ar.is
        and p.camp = ar.camp
        and p.ua_camp_id = ar.ua_camp_id
        and p.country = ar.country

查询计划是

XN Hash Join DS_DIST_BOTH (cost=11863664.64..218084556052252.12 rows=23020733790769 width=218)
    -> XN Seq Scan on tmp_predict p (cost=0.00..3954554.88 rows=395455488 width=188)
    -> XN Hash (cost=3954554.88..3954554.88 rows=395455488 width=165)
      -> XN Seq Scan on tmp_accumulate ar (cost=0.00..3954554.88 rows=395455488 width=165)

从上图中我们知道node-39 比其他节点拥有更多的数据。因为数据被join 倾斜。

为了解决这个问题,我们尝试使用update而不是join

update
  report.agg_info
set
  acc_re = ar.acc_re,
  iap_rev = ar.iap_rev,
  rev = ar.rev
from
  tmp_accumulate ar
where
  report.agg_info.pd = ar.pd
  and report.agg_info.idate = ar.idate
  and report.agg_info.aid = ar.aid
  and report.agg_info.pf = ar.pf
  and report.agg_info.is = ar.is
  and report.agg_info.camp = ar.camp
  and report.agg_info.ua_camp_id = ar.ua_camp_id
  and report.agg_info.country = ar.country

查询计划

XN Hash Join DS_BCAST_INNER (cost=11863664.64..711819961371132.00 rows=91602 width=254)
    -> XN Seq Scan on agg_info (cost=0.00..2.70 rows=270 width=224)
    -> XN Hash (cost=3954554.88..3954554.88 rows=395455488 width=170)
      -> XN Seq Scan on tmp_accumulate ar (cost=0.00..3954554.88 rows=395455488 width=170)

数据按照图片均匀分布在所有节点上。但是,每个节点中的数据更多。

我想知道,在 Redshift 中有没有通过 join 处理数据倾斜的最佳实践?

【问题讨论】:

标签: sql join amazon-redshift


【解决方案1】:

https://docs.aws.amazon.com/redshift/latest/dg/c-analyzing-the-query-plan.html

寻找以下有高成本运营的广播运营商:
• DS_BCAST_INNER:表示该表被广播到所有计算节点,这对于小表来说很好,但对于大表来说并不理想。
• DS_DIST_ALL_INNER:表示所有工作负载都在一个切片上。
• DS_DIST_BOTH:表示重分配。

DS_DIST_BOTH 在您的第一个查询中将两个表重新分布在特定列上。您尚未包含在EXPLAIN sn-p 中选择的列,但它可能是连接中的第一列。

DS_BCAST_INNER 正在向每个节点广播tmp_accumulate完整 副本。这两种操作都非常昂贵且缓慢。

您的连接范围很广,第一列似乎很倾斜。您可以尝试 2 种方法来解决偏差并阻止广播:

  1. 更改连接中声明的列的顺序,以首先声明唯一(或最不倾斜)列。第一列通常用作重新分发键。 (注意:如果表已经是 diststyle 键,这将不起作用。)
  2. 推荐。由于连接是如此复杂和倾斜,您可以预先计算这些列之间的哈希值,然后在该值上连接。
--Example of Pre-Calculated Hash
CREATE TEMP TABLE tmp_predict 
    DISTKEY(dist_hash)
AS SELECT FUNC_SHA1(pd||idate::VARCHAR||aid::VARCHAR||pf::VARCHAR
                      ||is::VARCHAR||camp::VARCHAR||ua_camp_id::VARCHAR
                      ||country::VARCHAR) dist_hash
         ,pd ,idate ,aid ,pf ,is ,camp ,ua_camp_id, country
         ,…
     FROM …
;
CREATE TEMP TABLE tmp_accumulate 
    DISTKEY(dist_hash)
AS SELECT FUNC_SHA1(pd||idate::VARCHAR||aid::VARCHAR||pf::VARCHAR
                      ||is::VARCHAR||camp::VARCHAR||ua_camp_id::VARCHAR
                      ||country::VARCHAR) dist_hash
         ,pd ,idate ,aid ,pf ,is ,camp ,ua_camp_id, country
         ,…
     FROM …
;
INSERT INTO report.agg_info
SELECT …
FROM    tmp_predict p
JOIN    tmp_accumulate ar
    ON  p.dist_hash = ar.dist_hash
;

【讨论】:

  • 我之前不知道FUNC_SHA1,这个解决方案让我省了很多。非常感谢...
【解决方案2】:

数据有偏差,因为您要加入的表似乎将所有数据都放在一个节点上。这可能是因为缺少 DISTKEY,或者是因为 DISTKEY 高度偏斜。

因此,您可以使用 DISTSTYLE EVEN 将该表的数据均匀分布在所有节点上,或者选择一个不同的 DISTKEY,它在数据中分布得更多。

【讨论】:

  • 实际上,tmp_accumulatetmp_predict 都是 diststyle。而当join
  • 给定一列值的 70% 是 abc,而这一列是 join 条件之一。如何使用DISTKEY
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-01
  • 1970-01-01
  • 2022-12-02
相关资源
最近更新 更多