PostgreSQL中create

60次阅读
没有评论

共计 7874 个字符,预计需要花费 20 分钟才能阅读完成。

这篇文章主要讲解了“PostgreSQL 中 create_sort_plan 函数实现逻辑是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着丸趣 TV 小编的思路慢慢深入,一起来研究和学习“PostgreSQL 中 create_sort_plan 函数实现逻辑是什么”吧!

一、数据结构

Plan
所有计划节点通过将 Plan 结构作为第一个字段从 Plan 结构“派生”。这确保了在将节点转换为计划节点时,一切都能正常工作。(在执行器中以通用方式传递时,节点指针经常被转换为 Plan *)

/* ----------------
 * Plan node
 *
 * All plan nodes  derive  from the Plan structure by having the
 * Plan structure as the first field. This ensures that everything works
 * when nodes are cast to Plan s. (node pointers are frequently cast to Plan*
 * when passed around generically in the executor)
 *  所有计划节点通过将 Plan 结构作为第一个字段从 Plan 结构“派生”。 *  这确保了在将节点转换为计划节点时,一切都能正常工作。 * (在执行器中以通用方式传递时,节点指针经常被转换为 Plan *)
 *
 * We never actually instantiate any Plan nodes; this is just the common
 * abstract superclass for all Plan-type nodes.
 *  从未实例化任何 Plan 节点; 这只是所有 Plan-type 节点的通用抽象超类。 * ----------------
 */
typedef struct Plan
 NodeTag type;// 节点类型
 /*
 *  成本估算信息;estimated execution costs for plan (see costsize.c for more info)
 */
 Cost startup_cost; /*  启动成本;cost expended before fetching any tuples */
 Cost total_cost; /*  总成本;total cost (assuming all tuples fetched) */
 /*
 *  优化器估算信息;planner s estimate of result size of this plan step
 */
 double plan_rows; /*  行数;number of rows plan is expected to emit */
 int plan_width; /*  平均行大小 (Byte 为单位);average row width in bytes */
 /*
 *  并行执行相关的信息;information needed for parallel query
 */
 bool parallel_aware; /*  是否参与并行执行逻辑?engage parallel-aware logic? */
 bool parallel_safe; /*  是否并行安全;OK to use as part of parallel plan? */
 /*
 * Plan 类型节点通用的信息.Common structural data for all Plan types.
 */
 int plan_node_id; /* unique across entire final plan tree */
 List *targetlist; /* target list to be computed at this node */
 List *qual; /* implicitly-ANDed qual conditions */
 struct Plan *lefttree; /* input plan tree(s) */
 struct Plan *righttree;
 List *initPlan; /* Init Plan nodes (un-correlated expr
 * subselects) */
 /*
 * Information for management of parameter-change-driven rescanning
 * parameter-change-driven 重扫描的管理信息.
 * 
 * extParam includes the paramIDs of all external PARAM_EXEC params
 * affecting this plan node or its children. setParam params from the
 * node s initPlans are not included, but their extParams are.
 *
 * allParam includes all the extParam paramIDs, plus the IDs of local
 * params that affect the node (i.e., the setParams of its initplans).
 * These are _all_ the PARAM_EXEC params that affect this node.
 */
 Bitmapset *extParam;
 Bitmapset *allParam;
} Plan;

二、源码解读

create_plan- create_plan_recurse- create_projection_plan 函数创建计划树, 执行投影操作并通过递归的方式为子访问路径生成执行计划。create_sort_plan 函数创建 Sort 计划节点。

//---------------------------------------------------------------- create_projection_plan
 * create_projection_plan
 *
 * Create a plan tree to do a projection step and (recursively) plans
 * for its subpaths. We may need a Result node for the projection,
 * but sometimes we can just let the subplan do the work.
 *  创建计划树, 执行投影操作并通过递归的方式为子访问路径生成执行计划.
 *  一般来说需要一个 Result 节点用于投影操作, 但有时候可以让子计划执行此项任务.
 */
static Plan *
create_projection_plan(PlannerInfo *root, ProjectionPath *best_path, int flags)
 Plan *plan;
 Plan *subplan;
 List *tlist;
 bool needs_result_node = false;
 /*
 * Convert our subpath to a Plan and determine whether we need a Result
 * node.
 *  转换 subpath 为 Plan, 并确定是否需要 Result 节点.
 *
 * In most cases where we don t need to project, creation_projection_path
 * will have set dummypp, but not always. First, some createplan.c
 * routines change the tlists of their nodes. (An example is that
 * create_merge_append_plan might add resjunk sort columns to a
 * MergeAppend.) Second, create_projection_path has no way of knowing
 * what path node will be placed on top of the projection path and
 * therefore can t predict whether it will require an exact tlist. For
 * both of these reasons, we have to recheck here.
 *  在大多数情况下,我们不需要投影运算,creation_projection_path 将设置 dummypp 标志,但并不总是如此。
 *  首先, 一些 createplan.c 中的函数更改其节点的 tlist。
 * (例如,create_merge_append_plan 可能会向 MergeAppend 添加 resjunk sort 列)。
 *  其次,create_projection_path 无法知道将在投影路径顶部放置哪些路径节点,因此无法预测它是否需要一个确切的 tlist。
 *  由于这两个原因,我们不得不在这里重新检查。
 */
 if (use_physical_tlist(root,  best_path- path, flags))
 {
 /*
 * Our caller doesn t really care what tlist we return, so we don t
 * actually need to project. However, we may still need to ensure
 * proper sortgroupref labels, if the caller cares about those.
 *  如果我们的调用者并不关心返回的结果 tlist,所以实际上不需要投影运算。
 *  然而,如果调用者关心 sortgroupref 标签,可能仍然需要确保正确的 sortgroupref 数据。
 */
 subplan = create_plan_recurse(root, best_path- subpath, 0);
 tlist = subplan- targetlist;
 if (flags   CP_LABEL_TLIST)
 apply_pathtarget_labeling_to_tlist(tlist,
 best_path- path.pathtarget);
 }
 else if (is_projection_capable_path(best_path- subpath))
 {
 /*
 * Our caller requires that we return the exact tlist, but no separate
 * result node is needed because the subpath is projection-capable.
 * Tell create_plan_recurse that we re going to ignore the tlist it
 * produces.
 *  调用者要求返回精确的 tlist,但是不需要单独的 Result 节点,因为子路径支持投影。
 *  调用 create_plan_recurse 时忽略它生成的 tlist。
 */
 subplan = create_plan_recurse(root, best_path- subpath,
 CP_IGNORE_TLIST);
 tlist = build_path_tlist(root,  best_path- path);
 }
 else
 {
 /*
 * It looks like we need a result node, unless by good fortune the
 * requested tlist is exactly the one the child wants to produce.
 *  看起来需要一个 Result 节点,除非幸运的是,请求的 tlist 正是子节点想要生成的。
 */
 subplan = create_plan_recurse(root, best_path- subpath, 0);
 tlist = build_path_tlist(root,  best_path- path);
 needs_result_node = !tlist_same_exprs(tlist, subplan- targetlist);
 }
 /*
 * If we make a different decision about whether to include a Result node
 * than create_projection_path did, we ll have made slightly wrong cost
 * estimates; but label the plan with the cost estimates we actually used,
 * not  corrected  ones. (XXX this could be cleaned up if we moved more
 * of the sortcolumn setup logic into Path creation, but that would add
 * expense to creating Paths we might end up not using.)
 *  如果我们对是否包含一个 Result 节点做出与 create_projection_path 不同的决定,
 *  我们就会做出略微错误的成本估算;
 *  但是在这个计划上标上我们实际使用的成本估算,而不是“修正的”成本估算。
 * (如果我们将更多的 sortcolumn 设置逻辑移到路径创建中,这个问题就可以解决了,
 *  但是这会增加创建路径的成本,而最终可能不会使用这些路径。)
 */
 if (!needs_result_node)
 {
 /* Don t need a separate Result, just assign tlist to subplan */
 // 不需要单独的 Result 节点, 把 tlist 赋值给 subplan
 plan = subplan;
 plan- targetlist = tlist;
 /* Label plan with the estimated costs we actually used */
 // 标记估算成本
 plan- startup_cost = best_path- path.startup_cost;
 plan- total_cost = best_path- path.total_cost;
 plan- plan_rows = best_path- path.rows;
 plan- plan_width = best_path- path.pathtarget- width;
 plan- parallel_safe = best_path- path.parallel_safe;
 /* ... but don t change subplan s parallel_aware flag */
 }
 else
 {
 /* We need a Result node */
 // 需要 Result 节点
 plan = (Plan *) make_result(tlist, NULL, subplan);
 copy_generic_path_info(plan, (Path *) best_path);
 }
 return plan;
//---------------------------------------------------------------- create_sort_plan
 /*
 * create_sort_plan
 *
 * Create a Sort plan for  best_path  and (recursively) plans
 * for its subpaths.
 *  创建 Sort 计划节点
 */
 static Sort *
 create_sort_plan(PlannerInfo *root, SortPath *best_path, int flags)
 {
 Sort *plan;
 Plan *subplan;
 
 /*
 * We don t want any excess columns in the sorted tuples, so request a
 * smaller tlist. Otherwise, since Sort doesn t project, tlist
 * requirements pass through.
 *  我们不希望在排序元组中有任何多余的列,所以希望得到一个更小的 tlist。
 *  否则,由于 Sort 不执行投影运算,tlist 就会通过完整的保留传递。
 */
 subplan = create_plan_recurse(root, best_path- subpath,
 flags | CP_SMALL_TLIST);
 
 /*
 * make_sort_from_pathkeys() indirectly calls find_ec_member_for_tle(),
 * which will ignore any child EC members that don t belong to the given
 * relids. Thus, if this sort path is based on a child relation, we must
 * pass its relids.
 * make_sort_from_pathkeys() 间接调用 find_ec_member_for_tle(),它将忽略不属于给定 relid 的任何子 EC 成员。
 *  因此,如果这个排序路径是基于子关系的,我们必须传递它的 relids。
 */
 plan = make_sort_from_pathkeys(subplan, best_path- path.pathkeys,
 IS_OTHER_REL(best_path- subpath- parent) ?
 best_path- path.parent- relids : NULL);
 
 copy_generic_path_info(plan- plan, (Path *) best_path);
 
 return plan;
 }

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-20发表,共计7874字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)