Greenplum中数据分布策略

由于Greenplum为Shared Nothing架构,每个节点都有自己的CPU/内存/硬盘等,不存在共享资源,所以数据的分布显得尤为重要。

分布策略

Greenplum中数据分布策略基本分为三种(附加一种):

  • 随机分布-distributed randomly:随机分布会将数据行按到来顺序依次循环发送到各个segment上。虽然随机分布确保了数据的平均分布,但只要有可能,应该尽量选择哈希分布策略,哈希分布的性能更加优良。需要注意:如果表存在主键,不能再使用随机分布,否则不能保证数据(主键)的唯一性。
  • 哈希分布-distributed by (col1[,col2...]):散列算法使分布键将每一行分配给特定segment。相同值的键将始终散列到同一个segment。选择唯一的分布键(例如Primary Key)将确保较均匀的数据分布。哈希分布是表的默认分布策略。哈希分布的基本思想是将数据随机分布到各个分片中,从而实现负载均衡和并行查询。Greenplum 中提供了多种哈希函数,包括 md5sha1sha256 等,可以根据实际情况选择适合的哈希函数。需要注意的是:在进行表的哈希分布时,需要指定分布的列;如果未指定分布列,系统会默认选择主键进行哈希分布;如果表不存在主键,则根据表的第一列进行哈希分布。分布键选择是否恰当是Greenplum能否发挥性能的主要因素,适合的分布键将数据均匀分布到各个 segment 上,避免数据倾斜。
  • 复制分布-distributed replicated:这种分布策略是GPDB 6的新增特性。Greenplum数据库将每行数据分配到每个segment上。这种分布策略下,表数据将均匀分布,因为每个segment都存储着同样的数据行。适合于小表。常见的系统视图表为复制分布(即非分布表)。
  • 范围分布-distributed by range:按照指定的数据分布键将表中的数据按照一定的范围进行分区,并将每个分区分配到不同的数据分片中。这种分布方式适用于按照时间范围等方式对数据进行分区的场景。

数据分布实验:

实验背景:使用以下sql建立三种类型的表:test_dis_by(哈希分布)、test_dis_ran(随机分布)、test_dis_rep(复制分布)

----------------------------------------------哈希分布
--创建表
create table test_dis_by(
id int,
name varchar(30),
beiy1 varchar(100),
beiy2 varchar(100),
CONSTRAINT pk_dis_ran primary key(id)
) distributed by(id);
--插入测试数据
insert into test_dis_by(id,name)
select 
gs,'name-'||gs
from generate_series(1, 10000) gs;
--查看数据分布情况
select tbd.*,gp_segment_id from test_dis_by tbd order by gp_segment_id asc,id asc;

select 
gp_segment_id,count(*)
from test_dis_by
group by gp_segment_id;


----------------------------------------------随机分布
--创建表  注意不能带主键
create table test_dis_ran(
id int,
name varchar(30),
beiy1 varchar(100),
beiy2 varchar(100)
) distributed randomly;
--插入测试数据
insert into test_dis_ran(id,name)
select 
gs,'name-'||gs
from generate_series(1, 10000) gs;
--查看数据分布情况
select tbd.*,gp_segment_id from test_dis_ran tbd order by gp_segment_id asc,id asc;

select 
gp_segment_id,count(*)
from test_dis_by
group by gp_segment_id;


----------------------------------------------复制分布
--创建表
create table public.test_dis_rep(
id int,
name varchar(30),
beiy1 varchar(100),
beiy2 varchar(100)
) distributed replicated;
--插入测试数据
insert into test_dis_rep(id,name)
select 
gs,'name-'||gs
from generate_series(1, 10000) gs;
--查看数据分布情况
这个sql报错因为是非分布式表,故不存在节点分布情况
select tbd.*,gp_segment_id from test_dis_rep tbd order by gp_segment_id asc,id asc;

数据重分布

这是Greenplum的一个特性,由于架构为shared-nothing,节点间数据不共享,如果存在多表联合查询,数据分布在不同节点上,greenplum如何实现呢?

查看以下案例,创建表test_by(根据id进行哈希分布)、test_ran(随机分布)

实验一  

背景:test_by(根据id进行哈希分布)与上一步骤的表test_dis_by(根据id进行哈希分布)进行联合查询

--创建test_by
create table test_by(
id int,
name varchar(30),
CONSTRAINT pk_test_by primary key(id)
) distributed by(id);
insert into test_by(id,name)
select 
gs,'name-'||gs
from generate_series(1, 100) gs;
select * from test_by order by gp_segment_id asc,id asc;

--查看执行计划
explain
select tdb.*
from test_dis_by tdb 
join test_by tb on tdb.id = tb.id;


QUERY PLAN
Gather Motion 4:1  (slice1; segments: 4)  (cost=0.00..862.58 rows=100 width=13)
  ->  Hash Join  (cost=0.00..862.58 rows=25 width=13)
        Hash Cond: (test_dis_by.id = test_by.id)
        ->  Seq Scan on test_dis_by  (cost=0.00..431.06 rows=2500 width=13)
        ->  Hash  (cost=431.00..431.00 rows=25 width=4)
              ->  Seq Scan on test_by  (cost=0.00..431.00 rows=25 width=4)
Optimizer: Pivotal Optimizer (GPORCA)

查看执行计划:分别在各个节点进行顺序扫描,最后通过Gather将结果返回给主节点,并未进行数据重分布。

实验二

背景:test_ran(随机分布)与上一步骤的表test_dis_by(根据id进行哈希分布)进行联合查询

--创建表test_ran
create table test_ran(
id int,
name varchar(30)
) distributed randomly;
insert into test_ran(id,name)
select 
gs,'name-'||gs
from generate_series(1, 100) gs;
select * from test_ran order by gp_segment_id asc,id asc;

--联合查询查询计划
explain
select tdb.*
from test_dis_by tdb 
join test_ran tr on tdb.id = tr.id;


QUERY PLAN
Gather Motion 4:1  (slice2; segments: 4)  (cost=0.00..862.59 rows=100 width=13)
  ->  Hash Join  (cost=0.00..862.58 rows=25 width=13)
        Hash Cond: (test_dis_by.id = test_ran.id)
        ->  Seq Scan on test_dis_by  (cost=0.00..431.06 rows=2500 width=13)
        ->  Hash  (cost=431.00..431.00 rows=25 width=4)
              ->  Redistribute Motion 4:4  (slice1; segments: 4)  (cost=0.00..431.00 rows=25 width=4)
                    Hash Key: test_ran.id
                    ->  Seq Scan on test_ran  (cost=0.00..431.00 rows=25 width=4)
Optimizer: Pivotal Optimizer (GPORCA)

查看执行计划,发现多了一行

              ->  Redistribute Motion 4:4  (slice1; segments: 4)  (cost=0.00..431.00 rows=25 width=4)

进行了数据重新分布。由于test_ran为随机分布,两表关联条件为 join using(id) ,数据分布在不同节点上,需要进行数据的重分布。

跨库关联

Greenplum两种实现策略:

  • 数据重分布- Redistribute Motion :按照关联字段重新分布
  • 广播模式-Broadcast Motion:每个节点复制一份数据。应用场景为:小表或者笛卡尔积时。

待完善.....

猜你喜欢

转载自blog.csdn.net/wangning0714/article/details/131001105