standard_planner
发布日期:2021-06-29 18:40:23 浏览次数:2 分类:技术文章

本文共 7786 字,大约阅读时间需要 25 分钟。

数据结构

PlannerGlobal

  • Global information for planning/optimization
  • PlannerGlobal holds state for an entire planner invocation;
  • this state is shared across all levels of sub-Queries that exist in the command being planned

PlannerInfo

  • information for planning a particular Query
  • (we make a separate PlannerInfo node for each sub-Query)
PlannedStmt *standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams){
PlannedStmt *result; PlannerGlobal *glob; double tuple_fraction; PlannerInfo *root; RelOptInfo *final_rel; Path *best_path; Plan *top_plan; ListCell *lp, *lr; /* * Set up global state for this planner invocation. This data is needed * across all levels of sub-Query that might exist in the given command, * so we keep it in a separate struct that's linked to by each per-Query * PlannerInfo. */ //设置这个planner的全局状态 glob = makeNode(PlannerGlobal); glob->boundParams = boundParams; glob->subplans = NIL; glob->subroots = NIL; glob->rewindPlanIDs = NULL; glob->finalrtable = NIL; glob->finalrowmarks = NIL; glob->resultRelations = NIL; glob->nonleafResultRelations = NIL; glob->rootResultRelations = NIL; glob->relationOids = NIL; glob->invalItems = NIL; glob->paramExecTypes = NIL; glob->lastPHId = 0; glob->lastRowMarkId = 0; glob->lastPlanNodeId = 0; glob->transientPlan = false; glob->dependsOnRole = false; /* * Assess whether it's feasible to use parallel mode for this query. We * can't do this in a standalone backend, or if the command will try to * modify any data, or if this is a cursor operation, or if GUCs are set * to values that don't permit parallelism, or if parallel-unsafe * functions are present in the query tree. * * (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE * MATERIALIZED VIEW to use parallel plans, but this is safe only because * the command is writing into a completely new table which workers won't * be able to see. If the workers could see the table, the fact that * group locking would cause them to ignore the leader's heavyweight * relation extension lock and GIN page locks would make this unsafe. * We'll have to fix that somehow if we want to allow parallel inserts in * general; updates and deletes have additional problems especially around * combo CIDs.) * * For now, we don't try to use parallel mode if we're running inside a * parallel worker. We might eventually be able to relax this * restriction, but for now it seems best not to have parallel workers * trying to create their own parallel workers. * * We can't use parallelism in serializable mode because the predicate * locking code is not parallel-aware. It's not catastrophic if someone * tries to run a parallel plan in serializable mode; it just won't get * any workers and will run serially. But it seems like a good heuristic * to assume that the same serialization level will be in effect at plan * time and execution time, so don't generate a parallel plan if we're in * serializable mode. */ if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 && IsUnderPostmaster && dynamic_shared_memory_type != DSM_IMPL_NONE && parse->commandType == CMD_SELECT && !parse->hasModifyingCTE && max_parallel_workers_per_gather > 0 && !IsParallelWorker() && !IsolationIsSerializable()) {
/* all the cheap tests pass, so scan the query tree */ glob->maxParallelHazard = max_parallel_hazard(parse); glob->parallelModeOK = (glob->maxParallelHazard != PROPARALLEL_UNSAFE); } else {
/* skip the query tree scan, just assume it's unsafe */ glob->maxParallelHazard = PROPARALLEL_UNSAFE; glob->parallelModeOK = false; } /* * glob->parallelModeNeeded is normally set to false here and changed to * true during plan creation if a Gather or Gather Merge plan is actually * created (cf. create_gather_plan, create_gather_merge_plan). * * However, if force_parallel_mode = on or force_parallel_mode = regress, * then we impose parallel mode whenever it's safe to do so, even if the * final plan doesn't use parallelism. It's not safe to do so if the * query contains anything parallel-unsafe; parallelModeOK will be false * in that case. Note that parallelModeOK can't change after this point. * Otherwise, everything in the query is either parallel-safe or * parallel-restricted, and in either case it should be OK to impose * parallel-mode restrictions. If that ends up breaking something, then * either some function the user included in the query is incorrectly * labelled as parallel-safe or parallel-restricted when in reality it's * parallel-unsafe, or else the query planner itself has a bug. */ glob->parallelModeNeeded = glob->parallelModeOK && (force_parallel_mode != FORCE_PARALLEL_OFF); /* Determine what fraction of the plan is likely to be scanned */ if (cursorOptions & CURSOR_OPT_FAST_PLAN) {
/* * We have no real idea how many tuples the user will ultimately FETCH * from a cursor, but it is often the case that he doesn't want 'em * all, or would prefer a fast-start plan anyway so that he can * process some of the tuples sooner. Use a GUC parameter to decide * what fraction to optimize for. */ tuple_fraction = cursor_tuple_fraction; /* * We document cursor_tuple_fraction as simply being a fraction, which * means the edge cases 0 and 1 have to be treated specially here. We * convert 1 to 0 ("all the tuples") and 0 to a very small fraction. */ if (tuple_fraction >= 1.0) tuple_fraction = 0.0; else if (tuple_fraction <= 0.0) tuple_fraction = 1e-10; } else {
/* Default assumption is we need all the tuples */ tuple_fraction = 0.0; } /* primary planning entry point (may recurse for subqueries) */ root = subquery_planner(glob, parse, NULL, false, tuple_fraction); /* Select best Path and turn it into a Plan */ final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL); best_path = get_cheapest_fractional_path(final_rel, tuple_fraction);//是path结构体//下面是plan结构体 top_plan = create_plan(root, best_path); /* * If creating a plan for a scrollable cursor, make sure it can run * backwards on demand. Add a Material node at the top at need. */ if (cursorOptions & CURSOR_OPT_SCROLL) {
if (!ExecSupportsBackwardScan(top_plan)) top_plan = materialize_finished_plan(top_plan); } /* * Optionally add a Gather node for testing purposes, provided this is * actually a safe thing to do. */ if (force_parallel_mode != FORCE_PARALLEL_OFF && top_plan->parallel_safe) {
Gather *gather = makeNode(Gather); /* * If there are any initPlans attached to the formerly-top plan node, * move them up to the Gather node; same as we do for Material node in * materialize_finished_plan. */ gather->plan.initPlan = top_plan->initPlan; top_plan->initPlan = NIL; gather->plan.targetlist = top_plan->targetlist; gather->plan.qual = NIL; gather->plan.lefttree = top_plan; gather->plan.righttree = NULL; gather->num_workers = 1; gather->single_copy = true; gather->invisible = (force_parallel_mode == FORCE_PARALLEL_REGRESS); /* * Since this Gather has no parallel-aware descendants to signal to, * we don't need a rescan Param. */ gather->rescan_param = -1; /* * Ideally we'd use cost_gather here, but setting up dummy path data * to satisfy it doesn't seem much cleaner than knowing what it does. */ gather->plan.startup_cost = top_plan->startup_cost + parallel_setup_cost; gather->plan.total_cost = top_plan->total_cost + parallel_setup_cost + parallel_tuple_cost * top_plan->plan_rows; gather->plan.plan_rows = top_plan->plan_rows; gather->plan.plan_width = top_plan->plan_width; gather->plan.parallel_aware = false; gather->plan.parallel_safe = false; /* use parallel mode for parallel plans. */ root->glob->parallelModeNeeded = true; top_plan = &gather->plan; }

转载地址:https://cyj666.blog.csdn.net/article/details/104640067 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Makefile 中:= ?= += =的不同之处
下一篇:pgstrom如何工作

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年05月01日 19时26分39秒