diff options
author | Amit Langote <amitlan@postgresql.org> | 2025-01-30 11:57:32 +0900 |
---|---|---|
committer | Amit Langote <amitlan@postgresql.org> | 2025-01-30 11:57:32 +0900 |
commit | bb3ec16e14ded1d23a46d3c7e623a965164fa124 (patch) | |
tree | ed93693454d76eb62dcccfb9b5e6f519af52d53b /src/backend | |
parent | ba0da16bd054de854c200a2dfa0b21c70e0300cf (diff) | |
download | postgresql-bb3ec16e14ded1d23a46d3c7e623a965164fa124.tar.gz postgresql-bb3ec16e14ded1d23a46d3c7e623a965164fa124.zip |
Move PartitionPruneInfo out of plan nodes into PlannedStmt
This moves PartitionPruneInfo from plan nodes to PlannedStmt,
simplifying traversal by centralizing all PartitionPruneInfo
structures in a single list in it, which holds all instances for the
main query and its subqueries. Instead of plan nodes (Append or
MergeAppend) storing PartitionPruneInfo pointers, they now reference
an index in this list.
A bitmapset field is added to PartitionPruneInfo to store the RT
indexes corresponding to the apprelids field in Append or MergeAppend.
This allows execution pruning logic to verify that it operates on the
correct plan node, mainly to facilitate debugging.
Duplicated code in set_append_references() and
set_mergeappend_references() is refactored into a new function,
register_pruneinfo(). This updates RT indexes by applying rtoffet
and adds PartitionPruneInfo to the global list in PlannerGlobal.
By allowing pruning to be performed without traversing the plan tree,
this change lays the groundwork for runtime initial pruning to occur
independently of plan tree initialization.
Reviewed-by: Alvaro Herrera <alvherre@alvh.no-ip.org> (earlier version)
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Tomas Vondra <tomas@vondra.me>
Discussion: https://postgr.es/m/CA+HiwqFGkMSge6TgC9KQzde0ohpAycLQuV7ooitEEpbKB0O_mg@mail.gmail.com
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/executor/execMain.c | 1 | ||||
-rw-r--r-- | src/backend/executor/execParallel.c | 1 | ||||
-rw-r--r-- | src/backend/executor/execPartition.c | 17 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 1 | ||||
-rw-r--r-- | src/backend/executor/nodeAppend.c | 5 | ||||
-rw-r--r-- | src/backend/executor/nodeMergeAppend.c | 5 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 23 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 103 | ||||
-rw-r--r-- | src/backend/partitioning/partprune.c | 19 |
10 files changed, 112 insertions, 64 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index fb8dba3ab2c..1d27b840ca9 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -853,6 +853,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) ExecInitRangeTable(estate, rangeTable, plannedstmt->permInfos); estate->es_plannedstmt = plannedstmt; + estate->es_part_prune_infos = plannedstmt->partPruneInfos; /* * Next, build the ExecRowMark array from the PlanRowMark(s), if any. diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index ff4d9dd1bb3..9c313d81315 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -181,6 +181,7 @@ ExecSerializePlan(Plan *plan, EState *estate) pstmt->dependsOnRole = false; pstmt->parallelModeNeeded = false; pstmt->planTree = plan; + pstmt->partPruneInfos = estate->es_part_prune_infos; pstmt->rtable = estate->es_range_table; pstmt->permInfos = estate->es_rteperminfos; pstmt->resultRelations = NIL; diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 7e71d422a62..16aec59d0ec 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1786,6 +1786,9 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap) * Initialize data structure needed for run-time partition pruning and * do initial pruning if needed * + * 'relids' identifies the relation to which both the parent plan and the + * PartitionPruneInfo given by 'part_prune_index' belong. + * * On return, *initially_valid_subplans is assigned the set of indexes of * child subplans that must be initialized along with the parent plan node. * Initial pruning is performed here if needed and in that case only the @@ -1798,11 +1801,23 @@ adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap) PartitionPruneState * ExecInitPartitionPruning(PlanState *planstate, int n_total_subplans, - PartitionPruneInfo *pruneinfo, + int part_prune_index, + Bitmapset *relids, Bitmapset **initially_valid_subplans) { PartitionPruneState *prunestate; EState *estate = planstate->state; + PartitionPruneInfo *pruneinfo; + + /* Obtain the pruneinfo we need. */ + pruneinfo = list_nth_node(PartitionPruneInfo, estate->es_part_prune_infos, + part_prune_index); + + /* Its relids better match the plan node's or the planner messed up. */ + if (!bms_equal(relids, pruneinfo->relids)) + elog(ERROR, "wrong pruneinfo with relids=%s found at part_prune_index=%d contained in plan node with relids=%s", + bmsToString(pruneinfo->relids), part_prune_index, + bmsToString(relids)); /* We may need an expression context to evaluate partition exprs */ ExecAssignExprContext(estate, planstate); diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 7c539de5cf2..6aac6f3a872 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -118,6 +118,7 @@ CreateExecutorState(void) estate->es_rowmarks = NULL; estate->es_rteperminfos = NIL; estate->es_plannedstmt = NULL; + estate->es_part_prune_infos = NIL; estate->es_junkFilter = NULL; diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 0bd0e4e54d3..986ef34030a 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -135,7 +135,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags) appendstate->as_begun = false; /* If run-time partition pruning is enabled, then set that up now */ - if (node->part_prune_info != NULL) + if (node->part_prune_index >= 0) { PartitionPruneState *prunestate; @@ -146,7 +146,8 @@ ExecInitAppend(Append *node, EState *estate, int eflags) */ prunestate = ExecInitPartitionPruning(&appendstate->ps, list_length(node->appendplans), - node->part_prune_info, + node->part_prune_index, + node->apprelids, &validsubplans); appendstate->as_prune_state = prunestate; nplans = bms_num_members(validsubplans); diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index e152c9ee3a0..1468f942388 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -83,7 +83,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) mergestate->ps.ExecProcNode = ExecMergeAppend; /* If run-time partition pruning is enabled, then set that up now */ - if (node->part_prune_info != NULL) + if (node->part_prune_index >= 0) { PartitionPruneState *prunestate; @@ -94,7 +94,8 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags) */ prunestate = ExecInitPartitionPruning(&mergestate->ps, list_length(node->mergeplans), - node->part_prune_info, + node->part_prune_index, + node->apprelids, &validsubplans); mergestate->ms_prune_state = prunestate; nplans = bms_num_members(validsubplans); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 1106cd85f0c..816a2b2a576 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1227,7 +1227,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) ListCell *subpaths; int nasyncplans = 0; RelOptInfo *rel = best_path->path.parent; - PartitionPruneInfo *partpruneinfo = NULL; int nodenumsortkeys = 0; AttrNumber *nodeSortColIdx = NULL; Oid *nodeSortOperators = NULL; @@ -1378,6 +1377,9 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) subplans = lappend(subplans, subplan); } + /* Set below if we find quals that we can use to run-time prune */ + plan->part_prune_index = -1; + /* * If any quals exist, they may be useful to perform further partition * pruning during execution. Gather information needed by the executor to @@ -1401,16 +1403,14 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) } if (prunequal != NIL) - partpruneinfo = - make_partition_pruneinfo(root, rel, - best_path->subpaths, - prunequal); + plan->part_prune_index = make_partition_pruneinfo(root, rel, + best_path->subpaths, + prunequal); } plan->appendplans = subplans; plan->nasyncplans = nasyncplans; plan->first_partial_plan = best_path->first_partial_path; - plan->part_prune_info = partpruneinfo; copy_generic_path_info(&plan->plan, (Path *) best_path); @@ -1449,7 +1449,6 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, List *subplans = NIL; ListCell *subpaths; RelOptInfo *rel = best_path->path.parent; - PartitionPruneInfo *partpruneinfo = NULL; /* * We don't have the actual creation of the MergeAppend node split out @@ -1542,6 +1541,9 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, subplans = lappend(subplans, subplan); } + /* Set below if we find quals that we can use to run-time prune */ + node->part_prune_index = -1; + /* * If any quals exist, they may be useful to perform further partition * pruning during execution. Gather information needed by the executor to @@ -1557,13 +1559,12 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, Assert(best_path->path.param_info == NULL); if (prunequal != NIL) - partpruneinfo = make_partition_pruneinfo(root, rel, - best_path->subpaths, - prunequal); + node->part_prune_index = make_partition_pruneinfo(root, rel, + best_path->subpaths, + prunequal); } node->mergeplans = subplans; - node->part_prune_info = partpruneinfo; /* * If prepare_sort_from_pathkeys added sort columns, but we were told to diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 6803edd0854..8a474a50be7 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -555,6 +555,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions, result->dependsOnRole = glob->dependsOnRole; result->parallelModeNeeded = glob->parallelModeNeeded; result->planTree = top_plan; + result->partPruneInfos = glob->partPruneInfos; result->rtable = glob->finalrtable; result->permInfos = glob->finalrteperminfos; result->resultRelations = glob->resultRelations; diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 1e7b7bc6ffc..0868249be94 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -1732,6 +1732,53 @@ set_customscan_references(PlannerInfo *root, } /* + * register_partpruneinfo + * Subroutine for set_append_references and set_mergeappend_references + * + * Add the PartitionPruneInfo from root->partPruneInfos at the given index + * into PlannerGlobal->partPruneInfos and return its index there. + * + * Also update the RT indexes present in PartitionedRelPruneInfos to add the + * offset. + */ +static int +register_partpruneinfo(PlannerInfo *root, int part_prune_index, int rtoffset) +{ + PlannerGlobal *glob = root->glob; + PartitionPruneInfo *pinfo; + ListCell *l; + + Assert(part_prune_index >= 0 && + part_prune_index < list_length(root->partPruneInfos)); + pinfo = list_nth_node(PartitionPruneInfo, root->partPruneInfos, + part_prune_index); + + pinfo->relids = offset_relid_set(pinfo->relids, rtoffset); + foreach(l, pinfo->prune_infos) + { + List *prune_infos = lfirst(l); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *prelinfo = lfirst(l2); + + prelinfo->rtindex += rtoffset; + prelinfo->initial_pruning_steps = + fix_scan_list(root, prelinfo->initial_pruning_steps, + rtoffset, 1); + prelinfo->exec_pruning_steps = + fix_scan_list(root, prelinfo->exec_pruning_steps, + rtoffset, 1); + } + } + + glob->partPruneInfos = lappend(glob->partPruneInfos, pinfo); + + return list_length(glob->partPruneInfos) - 1; +} + +/* * set_append_references * Do set_plan_references processing on an Append * @@ -1783,27 +1830,13 @@ set_append_references(PlannerInfo *root, aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset); - if (aplan->part_prune_info) - { - foreach(l, aplan->part_prune_info->prune_infos) - { - List *prune_infos = lfirst(l); - ListCell *l2; - - foreach(l2, prune_infos) - { - PartitionedRelPruneInfo *pinfo = lfirst(l2); - - pinfo->rtindex += rtoffset; - pinfo->initial_pruning_steps = - fix_scan_list(root, pinfo->initial_pruning_steps, - rtoffset, 1); - pinfo->exec_pruning_steps = - fix_scan_list(root, pinfo->exec_pruning_steps, - rtoffset, 1); - } - } - } + /* + * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index. + * Also update the RT indexes present in it to add the offset. + */ + if (aplan->part_prune_index >= 0) + aplan->part_prune_index = + register_partpruneinfo(root, aplan->part_prune_index, rtoffset); /* We don't need to recurse to lefttree or righttree ... */ Assert(aplan->plan.lefttree == NULL); @@ -1865,27 +1898,13 @@ set_mergeappend_references(PlannerInfo *root, mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset); - if (mplan->part_prune_info) - { - foreach(l, mplan->part_prune_info->prune_infos) - { - List *prune_infos = lfirst(l); - ListCell *l2; - - foreach(l2, prune_infos) - { - PartitionedRelPruneInfo *pinfo = lfirst(l2); - - pinfo->rtindex += rtoffset; - pinfo->initial_pruning_steps = - fix_scan_list(root, pinfo->initial_pruning_steps, - rtoffset, 1); - pinfo->exec_pruning_steps = - fix_scan_list(root, pinfo->exec_pruning_steps, - rtoffset, 1); - } - } - } + /* + * Add PartitionPruneInfo, if any, to PlannerGlobal and update the index. + * Also update the RT indexes present in it to add the offset. + */ + if (mplan->part_prune_index >= 0) + mplan->part_prune_index = + register_partpruneinfo(root, mplan->part_prune_index, rtoffset); /* We don't need to recurse to lefttree or righttree ... */ Assert(mplan->plan.lefttree == NULL); diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index fa3c5b3c3bb..d3f60cc87c9 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -207,16 +207,20 @@ static void partkey_datum_from_expr(PartitionPruneContext *context, /* * make_partition_pruneinfo - * Builds a PartitionPruneInfo which can be used in the executor to allow - * additional partition pruning to take place. Returns NULL when - * partition pruning would be useless. + * Checks if the given set of quals can be used to build pruning steps + * that the executor can use to prune away unneeded partitions. If + * suitable quals are found then a PartitionPruneInfo is built and tagged + * onto the PlannerInfo's partPruneInfos list. + * + * The return value is the 0-based index of the item added to the + * partPruneInfos list or -1 if nothing was added. * * 'parentrel' is the RelOptInfo for an appendrel, and 'subpaths' is the list * of scan paths for its child rels. * 'prunequal' is a list of potential pruning quals (i.e., restriction * clauses that are applicable to the appendrel). */ -PartitionPruneInfo * +int make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, List *subpaths, List *prunequal) @@ -330,10 +334,11 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, * quals, then we can just not bother with run-time pruning. */ if (prunerelinfos == NIL) - return NULL; + return -1; /* Else build the result data structure */ pruneinfo = makeNode(PartitionPruneInfo); + pruneinfo->relids = bms_copy(parentrel->relids); pruneinfo->prune_infos = prunerelinfos; /* @@ -356,7 +361,9 @@ make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, else pruneinfo->other_subplans = NULL; - return pruneinfo; + root->partPruneInfos = lappend(root->partPruneInfos, pruneinfo); + + return list_length(root->partPruneInfos) - 1; } /* |