由于Greenplum为Shared Nothing架构,每个节点都有自己的CPU/内存/硬盘等,不存在共享资源,所以数据的分布显得尤为重要。
Greenplum中数据分布策略基本分为三种(附加一种):
md5
、sha1
、sha256
等,可以根据实际情况选择适合的哈希函数。需要注意的是:在进行表的哈希分布时,需要指定分布的列;如果未指定分布列,系统会默认选择主键进行哈希分布;如果表不存在主键,则根据表的第一列进行哈希分布。分布键选择是否恰当是Greenplum能否发挥性能的主要因素,适合的分布键将数据均匀分布到各个 segment 上,避免数据倾斜。实验背景:使用以下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两种实现策略:
待完善.....