• Greenplum广播与重分布原理


    Greenplum 的执行计划和 PostgreSQL 基本一致,但是在表关联的时候还是会有区别,因为 greenplum 中数据不同于 pg,greenplum 是将数据分布在多个节点上。所以当两表关联时关联列又不是表的分布键时就会出现表的广播和重分布。本文将详细介绍广播和重分布的区别及场景。

    在此之前,我们需要先了解下在 greenplum 中表之间分布式关联有哪些类型?
    表的分布式关联主要分为两大类:
    1、单库关联,即表的关联键和分布键一致,所以只需要在单个库中得到结果后再关联即可,因此也不会涉及到广播和重分布;
    2、跨库关联,即表的关联键和分布键不一致,因此数据需要重新分布来达到单库关联的效果,这也是本文主要讲解的地方。

    对于跨库关联又分为两种情况:
    2.1、一张表的关联键是分布列,另一张表不是;
    2.2、两张表的关联键均不是分布列。
    详细情况如下图所示 (a、b 两表中 c1 列是分布列):

    下面结合实例来讲解广播和重分布的原理及场景。
    构建环境:

    1. postgres=# CREATE table a(c1 int,c2 int)distributed by(c1);
    2. CREATE TABLE
    3. postgres=# CREATE table b(c1 int,c2 int)distributed by(c1);
    4. CREATE TABLE

    现在主要来看看跨库关联的两种情况:

    — 情况一:a.c1=b.c2

    即 a 表关联键是分布列,b 表不是。这种情况可以通过两种方法来实现表的关联:
    1、重分布:将 b 表按照 c2 字段将数据重新分布到每个节点上,然后再和 a 表关联。这种情况下重分布的数据量就是 b 表的数据量 N;
    2、广播:将 a 表上的数据进行广播,即每个节点都放一份全量数据,然后再和 b 表关联。这种情况下数据量大小就是 a 表数据量 M * 节点数 L。

    综上,我们可以得出结论:
    N > M L:选择广播;
    N < =M 
    L:选择重分布。

    下面用实例来验证下:
    —M = 20000,N = 15000,L=2:

    1. postgres=# insert into a select generate_series(1,20000),generate_series(1,20000);
    2. INSERT 0 20000
    3. postgres=# insert into b select generate_series(1,15000),generate_series(1,15000);
    4. INSERT 0 15000

    — 执行计划:重分布

    1. postgres=# EXPLAIN select * from a,b where a.c1=b.c2;
    2. QUERY PLAN
    3. ---------------------------------------------------------------------------------------------------------
    4. Gather Motion 2:1 (slice2; segments: 2) (cost=655.50..1117.00 rows=15000 width=16)
    5. -> Hash Join (cost=655.50..1117.00 rows=7500 width=16)
    6. Hash Cond: a.c1 = b.c2
    7. -> Seq Scan on a (cost=0.00..224.00 rows=10000 width=8)
    8. -> Hash (cost=468.00..468.00 rows=7500 width=8)
    9. -> Redistribute Motion 2:2 (slice1; segments: 2) (cost=0.00..468.00 rows=7500 width=8)
    10. Hash Key: b.c2
    11. -> Seq Scan on b (cost=0.00..168.00 rows=7500 width=8)
    12. Optimizer status: legacy query optimizer
    13. (9 rows)

    —M = 1000,N = 15000,L=2:

    1. postgres=# TRUNCATE a
    2. TRUNCATE TABLE
    3. postgres=# insert into a select generate_series(1,1000),generate_series(1,1000);
    4. INSERT 0 1000

    — 执行计划:广播

    1. postgres=# EXPLAIN select * from a,b where a.c1=b.c2;
    2. QUERY PLAN
    3. -----------------------------------------------------------------------------------------------------
    4. Gather Motion 2:1 (slice2; segments: 2) (cost=67.00..287.50 rows=1000 width=16)
    5. -> Hash Join (cost=67.00..287.50 rows=500 width=16)
    6. Hash Cond: b.c2 = a.c1
    7. -> Seq Scan on b (cost=0.00..168.00 rows=7500 width=8)
    8. -> Hash (cost=42.00..42.00 rows=1000 width=8)
    9. -> Broadcast Motion 2:2 (slice1; segments: 2) (cost=0.00..42.00 rows=1000 width=8)
    10. -> Seq Scan on a (cost=0.00..12.00 rows=500 width=8)
    11. Optimizer status: legacy query optimizer
    12. (8 rows)

    — 情况二:a.c2=b.c2

    即两表的关联键都不是分布键,这种情况也分两种方法:
    1、重分布:将表 a 和表 b 均按照 c2 列,将数据重分布到每个节点上,所以代价就是表 a 数据量 M + 表 b 数据量 N;
    2、广播:将数据量较少的表数据进行广播,因此代价就是 min (M,N) 节点数 L。
    综上,我们又可以得出此情况下的结论:
    M + N > min(M,N) 
    L:广播;
    M + N <= min (M,N) * L:重分布。

    —M = 15000,N = 15000,L=2:

    1. postgres=# insert into b select generate_series(1,15000),generate_series(1,15000);
    2. INSERT 0 15000
    3. postgres=# insert into a select generate_series(1,15000),generate_series(1,15000);
    4. INSERT 0 15000

    — 执行计划:重分布

    1. postgres=# EXPLAIN select * from a,b where a.c2 = b.c2;
    2. QUERY PLAN
    3. ---------------------------------------------------------------------------------------------------------
    4. Gather Motion 2:1 (slice3; segments: 2) (cost=655.50..1348.50 rows=15000 width=16)
    5. -> Hash Join (cost=655.50..1348.50 rows=7500 width=16)
    6. Hash Cond: a.c2 = b.c2
    7. -> Redistribute Motion 2:2 (slice1; segments: 2) (cost=0.00..468.00 rows=7500 width=8)
    8. Hash Key: a.c2
    9. -> Seq Scan on a (cost=0.00..168.00 rows=7500 width=8)
    10. -> Hash (cost=468.00..468.00 rows=7500 width=8)
    11. -> Redistribute Motion 2:2 (slice2; segments: 2) (cost=0.00..468.00 rows=7500 width=8)
    12. Hash Key: b.c2
    13. -> Seq Scan on b (cost=0.00..168.00 rows=7500 width=8)
    14. Optimizer status: legacy query optimizer
    15. (11 rows)

    —M = 1000,N = 15000,L=2:

    1. postgres=# TRUNCATE a;
    2. TRUNCATE TABLE
    3. postgres=# insert into a select generate_series(1,1000),generate_series(1,1000);
    4. INSERT 0 1000
    5. postgres=# ANALYZE a;
    6. ANALYZE

    — 执行计划:广播

    1. postgres=# EXPLAIN select * from a,b where a.c2 = b.c2;
    2. QUERY PLAN
    3. -----------------------------------------------------------------------------------------------------
    4. Gather Motion 2:1 (slice2; segments: 2) (cost=67.00..287.50 rows=1000 width=16)
    5. -> Hash Join (cost=67.00..287.50 rows=500 width=16)
    6. Hash Cond: b.c2 = a.c2
    7. -> Seq Scan on b (cost=0.00..168.00 rows=7500 width=8)
    8. -> Hash (cost=42.00..42.00 rows=1000 width=8)
    9. -> Broadcast Motion 2:2 (slice1; segments: 2) (cost=0.00..42.00 rows=1000 width=8)
    10. -> Seq Scan on a (cost=0.00..12.00 rows=500 width=8)
    11. Optimizer status: legacy query optimizer
    12. (8 rows)

    总结:

    当表的分布式关联涉及到关联键不是分布列的时候,就会出现表的广播和重分布:

    1、部分表的关联键不是分布列:N > M * L 则使用广播,反之使用重分布;

    2、所有表的关联键都不是分布列:M + N > min (M,N) * L 则使用广播,反之使用重分布。 

  • 相关阅读:
    java -- abstract
    面试题 16.20. T9键盘-力扣双百代码
    Laravel daily日志保留N天源码分析
    基于LLMs的多模态大模型(Visual ChatGPT,PICa,MM-REACT,MAGIC)
    基于 ACK Fluid 的混合云优化数据访问(一):场景与架构
    软考高级架构师下篇-17安全架构设计理论与实践
    第三章 Linux多线程开发 线程取消 属性 同步 互斥锁 死锁 读写锁 生产者消费者 信号量
    SSL证书优惠购买,HTTPS证书双11价格
    20.6 OpenSSL 套接字分发RSA公钥
    安防视频监控/视频集中存储EasyCVR平台级联时,下级平台未发流是什么原因?
  • 原文地址:https://blog.csdn.net/sosemseo/article/details/126784468