暂无图片
暂无图片
4
暂无图片
暂无图片
1
暂无图片

GPDB-内核特性-GP7动态分区裁剪

原创 闫宗帅 2023-07-16
280

GPDB-内核特性-动态分区裁剪

上文我们介绍了,GP7中ORCA不再支持动态分区裁剪。那么他的动态分区裁剪效果又是怎么实现的呢?GP7除ORCA优化器外还有PG优化器,他的动态分区裁剪执行计划由PG优化器生成。

1、PartitionSelectorState结构

动态分区裁剪的算子为PartitionSelector,我们看下相关数据结构:


执行器执行过程中,使用PartitionSelectorState来描述相关执行信息。其中Bitmapset part_prune_result为裁剪后分区表,也就是Append算子需要执行的子执行计划。PlanState ps中Plan *plan其实是PartitionSelector,除了Plan结构外,还有paramid,用来表示es_param_exec_vals[]数组的索引,也就是指向该PartitionSelectorState的地址。

Estate *state为整个执行计划树所共享,所以Append节点也可以访问到es_param_exec_vals[]数组,得到对应的PartitionSelectorState。如此,Append节点就可以得到分区裁剪的结果part_prune_result,并据此来选择扫描对应分区。

2、PartitionSelector算子


PartitionSelector算子扫描子节点,然后执行ExecAddMatchingSubPlans进行分区裁剪,裁剪结果存入part_prune_result bitmap中。扫描完后,会将PartitionSelector算子的PartitionSelectorState地址保存到es_param_exec_vals[ps->paramid]数组。

这就需要分析ps->paramid和Append的join_prune_paramids链表是怎么对应的。

3、Append算子

Estate*state::es_param_exec_vals[]是一个数组,而Append节点是如何定位到分区裁剪的PartitionSelectorState位于哪个数组中呢?也就是Append节点执行时,如何选择哪个子分区去执行呢?


1)看下上图第3步,ExecAppend首先通过node->choose_next_subplan选择一个子分区计划去执行

2)然后进入循环,扫描各个裁剪后的分区表,返回扫描到的tuple。

3)第4步,choose_next_subplan_locally函数完成找出匹配的分区子计划,由函数ExecFindMatchingSubPlans函数完成。主要看其入参:plan->join_prune_pramids

4)第5步,ExecFindMatchingSubPlans函数从plan->join_prune_paramids链表中拿到paramid值,此值作为数组索引,取到estate->es_param_exec_vals[paramid]。该值的value是个Datum类型,即PartitionSelectorState的地址。PartitionSelector算子会将动态裁剪后的分区序号放入part_prune_result中,据此可以在Append节点中获取到PartitionSelector算子的结果。

5)现在需要聚焦plan->join_prune_paramids链表是怎么存储PartitionSelector算子地址的。

6)第1步,create_nestloop_plan函数:push_partition_selector_candidate_for_join函数将candidate->selectors初始化NULL,需要继续分析下面的函数。create_plan_recurse会调用create_append_plan初始化Append计划节点。

7)第2步,create_append_plan函数:root->partition_selector_candidates链表 --> root->partition_selector_candidates->selectors::psinfo放到该selectors链表(psinfo->paramid即分配的paramid

8)返回第1步,create_append_plan执行完后,从root->partition_selector_candidates中取出psinfo,调用create_partition_selector_path创建PartitionSelector算子的Plan路径,psinfo的paramid会保存到PartitionSelector的paramid中。

9)第1步,执行完outerjoinpath的Plan创建,接着递归调用create_plan_recurse对innerjoinpath创建Plan,此时会调用create_partition_selector_plan创建其Plan:


将PartitionSelectorPath中的paramid赋值给ParitionSelector的paramid。这样ParitionSelector的paramid来自PartitionSelectorPath中的paramid,PartitionSelectorPath中的paramid来自root->partition_selector_candidates链表中的selectors链表(selectors链表的ParitionSelectorInfo中包含分配的paramid),ParitionSelectorInfo的paramid来自create_append_plan函数分配,并将其保存到root->partition_selector_candidates链表中的selectors链表。

4、总结

create_append_plan分配paramid,将其赋值给PartitionSelector的paramid;并将其放到Append的join_prune_paramids链表。PartitionSelector算子将分区表裁剪的结果放到part_prune_result中,并将其PartitionSelectorState的地址存入estate->es_param_exec_vals[paramid]数组。Append算子执行时,根据join_prune_paramids中的paramid获取estate->es_param_exec_vals[paramid],从而得到PartitionSelectorState,继而得到分区裁剪结果part_prune_result。由此,选择appendplans[]数组中的子计划执行。这样就完成了分区裁剪,仅扫描满足条件的子分区。


「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

筱悦星辰
暂无图片
1年前
评论
暂无图片 1
只做力所能及的事,是本能;勇于尝试新事物,才是本事。前行路上,勇敢挑战更高目标,既是一个人的智慧,也是一个人的胆略。
1年前
暂无图片 1
评论