GP6.5gpexpand对于增加新segment后,需要对表格做数据重分布。由于6.5中分布算法使用了jump consistency hash,使得重分布时跨节点的数据移动只发生在old segment到new segment,没有old segment之间的数据移动。这大大提高了重分布的效率,帮助降低了扩容窗口时间。
具体原理可以参考下面链接,其中第一个视频是来自Pivotal开发者杜佳伦的演讲:
https://www.bilibili.com/video/BV1PE411j7cp/?p=2
https://www.cnblogs.com/zhangrui153169/p/11435581.html
我翻看了一下GP6.5的代码,重分布是通过扩展一个EXPAND keyword来实现,
命令:ALTER TABLE mytbl EXPAND TABLE;
对应的内核函数:
tablecmds.c
ATExecCmd
AT_ExpandTable
ATExecExpandTableCTAS
参考AT_ExpandTable(), ATExecExpandTableCTAS()的注释及代码,重分布主要依赖下面的query来实现
CREATE TABLE tmp_tab_nam AS SELECT * FROM cur_table DISTRIBUTED BY (policy)
对于old segment上的数据,比较容易理解,通过此query可以创建一个临时表,把对应该segment的数据抽取出来。
我的问题是:
所谓的old segment到new segment的数据移动,通过这个query如何实现的呢?问题背景有点长,不好意思,谢谢。
注释:
代码:
ATExecExpandTableCTAS()
// build CTAS
// CREATE TABLE tmp_tab_nam AS SELECT * FROM cur_table DISTRIBUTED BY (policy)
make_distributedby_for_rel
distby->numsegments = getgpsegmentCount();
build_ctas_with_dist
// run on all nodes
ExecutorStart
ExecutorRun
// swap relfilenodes and MORE
swap_relation_files
// reindex
reindex_relation
// Drop the tmp table
performDeletion
这个create语句就会做数据的重分布,只是依然属于原来segment的数据发给原来的本地节点,属于新节点的数据才通过网络发给新节点。
@kainwen 非常感谢!
按照你的思路,实验了一下,基本明白了:)。推荐的视频也很有针对性。
我的环境信息:原有6个segment,扩容了3个segment
可以看到下面重分布的Redistribute Motion 6:9,表明重分布发生在old segments(6个)到old+new segments(9个),除了old segment到new segment的motion,理论上也包含old segment到old segment的motion。但是由于数据分布hash使用的是Jump consistency hash,能够保证新加segment,old segment之间不会发生数据移动,实际上最终motion只发生在old segment到new segment。
// 新表,旧表的numsegments 不同,
// 旧表对应old segments数量(6个)
// 新表对应old+new segments数量(9个)
mydw=# select * from gp_distribution_policy;
localoid | policytype | numsegments | distkey | distclass
----------+------------+-------------+---------+-----------
18188 | p | 6 | 1 | 10043
18208 | p | 9 | 1 | 10043
mydw=# explain insert into t2 select * from t1;
QUERY PLAN
------------------------------------------------------------------------------------------
Insert on t2 (cost=0.00..7.00 rows=12 width=32)
-> Redistribute Motion 6:9 (slice1; segments: 6) (cost=0.00..7.00 rows=17 width=32)
Hash Key: t1.uid
-> Seq Scan on t1 (cost=0.00..7.00 rows=17 width=32)
Optimizer: Postgres query optimizer
mydw=# explain create table tmp_t1 as select * from t1 DISTRIBUTED BY (uid);
QUERY PLAN
------------------------------------------------------------------------------------
Redistribute Motion 6:9 (slice1; segments: 6) (cost=0.00..7.00 rows=17 width=32)
Hash Key: uid
-> Seq Scan on t1 (cost=0.00..7.00 rows=17 width=32)
Optimizer: Postgres query optimizer