mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Assorted cosmetic cleanup of run-time-partition-pruning code.
Use "subplan" rather than "subnode" to refer to the child plans of a partitioning Append; this seems a bit more specific and hence clearer. Improve assorted comments. No non-cosmetic changes. David Rowley and Tom Lane Discussion: https://postgr.es/m/CAFj8pRBjrufA3ocDm8o4LPGNye9Y+pm1b9kCwode4X04CULG3g@mail.gmail.com
This commit is contained in:
@ -1334,9 +1334,9 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
|
||||
* Run-Time Partition Pruning Support.
|
||||
*
|
||||
* The following series of functions exist to support the removal of unneeded
|
||||
* subnodes for queries against partitioned tables. The supporting functions
|
||||
* here are designed to work with any node type which supports an arbitrary
|
||||
* number of subnodes, e.g. Append, MergeAppend.
|
||||
* subplans for queries against partitioned tables. The supporting functions
|
||||
* here are designed to work with any plan type which supports an arbitrary
|
||||
* number of subplans, e.g. Append, MergeAppend.
|
||||
*
|
||||
* When pruning involves comparison of a partition key to a constant, it's
|
||||
* done by the planner. However, if we have a comparison to a non-constant
|
||||
@ -1346,73 +1346,72 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
|
||||
*
|
||||
* We must distinguish expressions containing PARAM_EXEC Params from
|
||||
* expressions that don't contain those. Even though a PARAM_EXEC Param is
|
||||
* considered to be a stable expression, it can change value from one node
|
||||
* scan to the next during query execution. Stable comparison expressions
|
||||
* that don't involve such Params allow partition pruning to be done once
|
||||
* during executor startup. Expressions that do involve such Params require
|
||||
* us to prune separately for each scan of the parent plan node.
|
||||
* considered to be a stable expression, it can change value from one plan
|
||||
* node scan to the next during query execution. Stable comparison
|
||||
* expressions that don't involve such Params allow partition pruning to be
|
||||
* done once during executor startup. Expressions that do involve such Params
|
||||
* require us to prune separately for each scan of the parent plan node.
|
||||
*
|
||||
* Note that pruning away unneeded subnodes during executor startup has the
|
||||
* added benefit of not having to initialize the unneeded subnodes at all.
|
||||
* Note that pruning away unneeded subplans during executor startup has the
|
||||
* added benefit of not having to initialize the unneeded subplans at all.
|
||||
*
|
||||
*
|
||||
* Functions:
|
||||
*
|
||||
* ExecSetupPartitionPruneState:
|
||||
* This must be called by nodes before any partition pruning is
|
||||
* attempted. Normally executor startup is a good time. This function
|
||||
* creates the PartitionPruneState details which are required by each
|
||||
* of the two pruning functions, details include information about
|
||||
* how to map the partition index details which are returned by the
|
||||
* planner's partition prune function into subnode indexes.
|
||||
* Creates the PartitionPruneState required by each of the two pruning
|
||||
* functions. Details stored include how to map the partition index
|
||||
* returned by the partition pruning code into subplan indexes.
|
||||
*
|
||||
* ExecFindInitialMatchingSubPlans:
|
||||
* Returns indexes of matching subnodes. Partition pruning is attempted
|
||||
* Returns indexes of matching subplans. Partition pruning is attempted
|
||||
* without any evaluation of expressions containing PARAM_EXEC Params.
|
||||
* This function must be called during executor startup for the given
|
||||
* node before the subnodes themselves are initialized. Subnodes which
|
||||
* are found not to match by this function must not be included in the
|
||||
* node's list of subnodes as this function performs a remap of the
|
||||
* partition index to subplan index map and the newly created map
|
||||
* provides indexes only for subnodes which remain after calling this
|
||||
* function.
|
||||
* This function must be called during executor startup for the parent
|
||||
* plan before the subplans themselves are initialized. Subplans which
|
||||
* are found not to match by this function must be removed from the
|
||||
* plan's list of subplans during execution, as this function performs a
|
||||
* remap of the partition index to subplan index map and the newly
|
||||
* created map provides indexes only for subplans which remain after
|
||||
* calling this function.
|
||||
*
|
||||
* ExecFindMatchingSubPlans:
|
||||
* Returns indexes of matching subnodes after evaluating all available
|
||||
* expressions. This function can only be called while the executor is
|
||||
* running.
|
||||
* Returns indexes of matching subplans after evaluating all available
|
||||
* expressions. This function can only be called during execution and
|
||||
* must be called again each time the value of a Param listed in
|
||||
* PartitionPruneState's 'execparamids' changes.
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* ExecSetupPartitionPruneState
|
||||
* Setup the required data structure which is required for calling
|
||||
* Set up the data structure required for calling
|
||||
* ExecFindInitialMatchingSubPlans and ExecFindMatchingSubPlans.
|
||||
*
|
||||
* 'planstate' is the parent plan node's execution state.
|
||||
*
|
||||
* 'partitionpruneinfo' is a List of PartitionPruneInfos as generated by
|
||||
* make_partition_pruneinfo. Here we build a PartitionPruneContext for each
|
||||
* item in the List. These contexts can be re-used each time we re-evaulate
|
||||
* which partitions match the pruning steps provided in each
|
||||
* PartitionPruneInfo.
|
||||
* make_partition_pruneinfo. Here we build a PartitionPruneState containing a
|
||||
* PartitionPruningData for each item in that List. This data can be re-used
|
||||
* each time we re-evaluate which partitions match the pruning steps provided
|
||||
* in each PartitionPruneInfo.
|
||||
*/
|
||||
PartitionPruneState *
|
||||
ExecSetupPartitionPruneState(PlanState *planstate, List *partitionpruneinfo)
|
||||
{
|
||||
PartitionPruningData *prunedata;
|
||||
PartitionPruneState *prunestate;
|
||||
PartitionPruningData *prunedata;
|
||||
ListCell *lc;
|
||||
int i;
|
||||
|
||||
Assert(partitionpruneinfo != NIL);
|
||||
|
||||
/*
|
||||
* Allocate the data structure
|
||||
*/
|
||||
prunestate = (PartitionPruneState *) palloc(sizeof(PartitionPruneState));
|
||||
prunedata = (PartitionPruningData *)
|
||||
palloc(sizeof(PartitionPruningData) * list_length(partitionpruneinfo));
|
||||
|
||||
/*
|
||||
* The first item in the array contains the details for the query's target
|
||||
* partition, so record that as the root of the partition hierarchy.
|
||||
*/
|
||||
prunestate->partprunedata = prunedata;
|
||||
prunestate->num_partprunedata = list_length(partitionpruneinfo);
|
||||
prunestate->do_initial_prune = false; /* may be set below */
|
||||
@ -1420,11 +1419,10 @@ ExecSetupPartitionPruneState(PlanState *planstate, List *partitionpruneinfo)
|
||||
prunestate->execparamids = NULL;
|
||||
|
||||
/*
|
||||
* Create a sub memory context which we'll use when making calls to the
|
||||
* query planner's function to determine which partitions will match. The
|
||||
* planner is not too careful about freeing memory, so we'll ensure we
|
||||
* call the function in this context to avoid any memory leaking in the
|
||||
* executor's memory context.
|
||||
* Create a short-term memory context which we'll use when making calls to
|
||||
* the partition pruning functions. This avoids possible memory leaks,
|
||||
* since the pruning functions call comparison functions that aren't under
|
||||
* our control.
|
||||
*/
|
||||
prunestate->prune_context =
|
||||
AllocSetContextCreate(CurrentMemoryContext,
|
||||
@ -1448,8 +1446,8 @@ ExecSetupPartitionPruneState(PlanState *planstate, List *partitionpruneinfo)
|
||||
* We must make a copy of this rather than pointing directly to the
|
||||
* plan's version as we may end up making modifications to it later.
|
||||
*/
|
||||
pprune->subnode_map = palloc(sizeof(int) * pinfo->nparts);
|
||||
memcpy(pprune->subnode_map, pinfo->subnode_map,
|
||||
pprune->subplan_map = palloc(sizeof(int) * pinfo->nparts);
|
||||
memcpy(pprune->subplan_map, pinfo->subplan_map,
|
||||
sizeof(int) * pinfo->nparts);
|
||||
|
||||
/* We can use the subpart_map verbatim, since we never modify it */
|
||||
@ -1525,7 +1523,7 @@ ExecSetupPartitionPruneState(PlanState *planstate, List *partitionpruneinfo)
|
||||
|
||||
/*
|
||||
* Accumulate the IDs of all PARAM_EXEC Params affecting the
|
||||
* partitioning decisions at this node.
|
||||
* partitioning decisions at this plan node.
|
||||
*/
|
||||
prunestate->execparamids = bms_add_members(prunestate->execparamids,
|
||||
pinfo->execparamids);
|
||||
@ -1540,22 +1538,19 @@ ExecSetupPartitionPruneState(PlanState *planstate, List *partitionpruneinfo)
|
||||
|
||||
/*
|
||||
* ExecFindInitialMatchingSubPlans
|
||||
* Determine which subset of subplan nodes we need to initialize based
|
||||
* on the details stored in 'prunestate'. Here we only determine the
|
||||
* matching partitions using values known during plan startup, which
|
||||
* excludes any expressions containing PARAM_EXEC Params.
|
||||
* Identify the set of subplans that cannot be eliminated by initial
|
||||
* pruning (disregarding any pruning constraints involving PARAM_EXEC
|
||||
* Params). Also re-map the translation matrix which allows conversion
|
||||
* of partition indexes into subplan indexes to account for the unneeded
|
||||
* subplans having been removed.
|
||||
*
|
||||
* It is expected that callers of this function do so only once during their
|
||||
* init plan. The caller must only initialize the subnodes which are returned
|
||||
* by this function. The remaining subnodes should be discarded. Once this
|
||||
* function has been called, future calls to ExecFindMatchingSubPlans will
|
||||
* return its matching subnode indexes assuming that the caller discarded
|
||||
* the original non-matching subnodes.
|
||||
* Must only be called once per 'prunestate', and only if initial pruning
|
||||
* is required.
|
||||
*
|
||||
* 'nsubnodes' must be passed as the total number of unpruned subnodes.
|
||||
* 'nsubplans' must be passed as the total number of unpruned subplans.
|
||||
*/
|
||||
Bitmapset *
|
||||
ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubnodes)
|
||||
ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubplans)
|
||||
{
|
||||
PartitionPruningData *pprune;
|
||||
MemoryContext oldcontext;
|
||||
@ -1584,33 +1579,33 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubnodes)
|
||||
ResetExprContext(pprune->context.planstate->ps_ExprContext);
|
||||
|
||||
/*
|
||||
* If any subnodes were pruned, we must re-sequence the subnode indexes so
|
||||
* If any subplans were pruned, we must re-sequence the subplan indexes so
|
||||
* that ExecFindMatchingSubPlans properly returns the indexes from the
|
||||
* subnodes which will remain after execution of this function.
|
||||
* subplans which will remain after execution of this function.
|
||||
*/
|
||||
if (bms_num_members(result) < nsubnodes)
|
||||
if (bms_num_members(result) < nsubplans)
|
||||
{
|
||||
int *new_subnode_indexes;
|
||||
int *new_subplan_indexes;
|
||||
int i;
|
||||
int newidx;
|
||||
|
||||
/*
|
||||
* First we must build an array which we can use to adjust the
|
||||
* existing subnode_map so that it contains the new subnode indexes.
|
||||
* existing subplan_map so that it contains the new subplan indexes.
|
||||
*/
|
||||
new_subnode_indexes = (int *) palloc(sizeof(int) * nsubnodes);
|
||||
new_subplan_indexes = (int *) palloc(sizeof(int) * nsubplans);
|
||||
newidx = 0;
|
||||
for (i = 0; i < nsubnodes; i++)
|
||||
for (i = 0; i < nsubplans; i++)
|
||||
{
|
||||
if (bms_is_member(i, result))
|
||||
new_subnode_indexes[i] = newidx++;
|
||||
new_subplan_indexes[i] = newidx++;
|
||||
else
|
||||
new_subnode_indexes[i] = -1; /* Newly pruned */
|
||||
new_subplan_indexes[i] = -1; /* Newly pruned */
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we can re-sequence each PartitionPruneInfo's subnode_map so
|
||||
* that they point to the new index of the subnode.
|
||||
* Now we can re-sequence each PartitionPruneInfo's subplan_map so
|
||||
* that they point to the new index of the subplan.
|
||||
*/
|
||||
for (i = 0; i < prunestate->num_partprunedata; i++)
|
||||
{
|
||||
@ -1622,7 +1617,7 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubnodes)
|
||||
|
||||
/*
|
||||
* We also need to reset the present_parts field so that it only
|
||||
* contains partition indexes that we actually still have subnodes
|
||||
* contains partition indexes that we actually still have subplans
|
||||
* for. It seems easier to build a fresh one, rather than trying
|
||||
* to update the existing one.
|
||||
*/
|
||||
@ -1631,20 +1626,20 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubnodes)
|
||||
|
||||
for (j = 0; j < nparts; j++)
|
||||
{
|
||||
int oldidx = pprune->subnode_map[j];
|
||||
int oldidx = pprune->subplan_map[j];
|
||||
|
||||
/*
|
||||
* If this partition existed as a subnode then change the old
|
||||
* subnode index to the new subnode index. The new index may
|
||||
* If this partition existed as a subplan then change the old
|
||||
* subplan index to the new subplan index. The new index may
|
||||
* become -1 if the partition was pruned above, or it may just
|
||||
* come earlier in the subnode list due to some subnodes being
|
||||
* come earlier in the subplan list due to some subplans being
|
||||
* removed earlier in the list.
|
||||
*/
|
||||
if (oldidx >= 0)
|
||||
{
|
||||
pprune->subnode_map[j] = new_subnode_indexes[oldidx];
|
||||
pprune->subplan_map[j] = new_subplan_indexes[oldidx];
|
||||
|
||||
if (new_subnode_indexes[oldidx] >= 0)
|
||||
if (new_subplan_indexes[oldidx] >= 0)
|
||||
pprune->present_parts =
|
||||
bms_add_member(pprune->present_parts, j);
|
||||
}
|
||||
@ -1686,7 +1681,7 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubnodes)
|
||||
}
|
||||
}
|
||||
|
||||
pfree(new_subnode_indexes);
|
||||
pfree(new_subplan_indexes);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -1695,7 +1690,7 @@ ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, int nsubnodes)
|
||||
/*
|
||||
* ExecFindMatchingSubPlans
|
||||
* Determine which subplans match the pruning steps detailed in
|
||||
* 'pprune' for the current comparison expression values.
|
||||
* 'prunestate' for the current comparison expression values.
|
||||
*
|
||||
* Here we assume we may evaluate PARAM_EXEC Params.
|
||||
*/
|
||||
@ -1767,28 +1762,24 @@ find_matching_subplans_recurse(PartitionPruneState *prunestate,
|
||||
partset = pprune->present_parts;
|
||||
}
|
||||
|
||||
/* Translate partset into subnode indexes */
|
||||
/* Translate partset into subplan indexes */
|
||||
i = -1;
|
||||
while ((i = bms_next_member(partset, i)) >= 0)
|
||||
{
|
||||
if (pprune->subnode_map[i] >= 0)
|
||||
if (pprune->subplan_map[i] >= 0)
|
||||
*validsubplans = bms_add_member(*validsubplans,
|
||||
pprune->subnode_map[i]);
|
||||
pprune->subplan_map[i]);
|
||||
else
|
||||
{
|
||||
int partidx = pprune->subpart_map[i];
|
||||
|
||||
if (partidx != -1)
|
||||
if (partidx >= 0)
|
||||
find_matching_subplans_recurse(prunestate,
|
||||
&prunestate->partprunedata[partidx],
|
||||
initial_prune, validsubplans);
|
||||
else
|
||||
{
|
||||
/*
|
||||
* This could only happen if clauses used in planning where
|
||||
* more restrictive than those used here, or if the maps are
|
||||
* somehow corrupt.
|
||||
*/
|
||||
/* Shouldn't happen */
|
||||
elog(ERROR, "partition missing from subplans");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user