mirror of
https://github.com/postgres/postgres.git
synced 2025-06-17 17:02:08 +03:00
Expand run-time partition pruning to work with MergeAppend
This expands the support for the run-time partition pruning which was added
for Append in 499be013de
to also allow unneeded subnodes of a MergeAppend
to be removed.
Author: David Rowley
Discussion: https://www.postgresql.org/message-id/CAKJS1f_F_V8D7Wu-HVdnH7zCUxhoGK8XhLLtd%3DCu85qDZzXrgg%40mail.gmail.com
This commit is contained in:
@ -39,6 +39,7 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "executor/execdebug.h"
|
||||
#include "executor/execPartition.h"
|
||||
#include "executor/nodeMergeAppend.h"
|
||||
#include "lib/binaryheap.h"
|
||||
#include "miscadmin.h"
|
||||
@ -65,8 +66,10 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
|
||||
{
|
||||
MergeAppendState *mergestate = makeNode(MergeAppendState);
|
||||
PlanState **mergeplanstates;
|
||||
Bitmapset *validsubplans;
|
||||
int nplans;
|
||||
int i;
|
||||
int i,
|
||||
j;
|
||||
ListCell *lc;
|
||||
|
||||
/* check for unsupported flags */
|
||||
@ -78,19 +81,80 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
|
||||
*/
|
||||
ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
|
||||
|
||||
/*
|
||||
* Set up empty vector of subplan states
|
||||
*/
|
||||
nplans = list_length(node->mergeplans);
|
||||
|
||||
mergeplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
|
||||
|
||||
/*
|
||||
* create new MergeAppendState for our node
|
||||
*/
|
||||
mergestate->ps.plan = (Plan *) node;
|
||||
mergestate->ps.state = estate;
|
||||
mergestate->ps.ExecProcNode = ExecMergeAppend;
|
||||
mergestate->ms_noopscan = false;
|
||||
|
||||
/* If run-time partition pruning is enabled, then set that up now */
|
||||
if (node->part_prune_infos != NIL)
|
||||
{
|
||||
PartitionPruneState *prunestate;
|
||||
|
||||
/* We may need an expression context to evaluate partition exprs */
|
||||
ExecAssignExprContext(estate, &mergestate->ps);
|
||||
|
||||
prunestate = ExecCreatePartitionPruneState(&mergestate->ps,
|
||||
node->part_prune_infos);
|
||||
mergestate->ms_prune_state = prunestate;
|
||||
|
||||
/* Perform an initial partition prune, if required. */
|
||||
if (prunestate->do_initial_prune)
|
||||
{
|
||||
/* Determine which subplans survive initial pruning */
|
||||
validsubplans = ExecFindInitialMatchingSubPlans(prunestate,
|
||||
list_length(node->mergeplans));
|
||||
|
||||
/*
|
||||
* The case where no subplans survive pruning must be handled
|
||||
* specially. The problem here is that code in explain.c requires
|
||||
* an Append to have at least one subplan in order for it to
|
||||
* properly determine the Vars in that subplan's targetlist. We
|
||||
* sidestep this issue by just initializing the first subplan and
|
||||
* setting ms_noopscan to true to indicate that we don't really
|
||||
* need to scan any subnodes.
|
||||
*/
|
||||
if (bms_is_empty(validsubplans))
|
||||
{
|
||||
mergestate->ms_noopscan = true;
|
||||
|
||||
/* Mark the first as valid so that it's initialized below */
|
||||
validsubplans = bms_make_singleton(0);
|
||||
}
|
||||
|
||||
nplans = bms_num_members(validsubplans);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We'll need to initialize all subplans */
|
||||
nplans = list_length(node->mergeplans);
|
||||
validsubplans = bms_add_range(NULL, 0, nplans - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* If no runtime pruning is required, we can fill ms_valid_subplans
|
||||
* immediately, preventing later calls to ExecFindMatchingSubPlans.
|
||||
*/
|
||||
if (!prunestate->do_exec_prune)
|
||||
mergestate->ms_valid_subplans = bms_add_range(NULL, 0, nplans - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
nplans = list_length(node->mergeplans);
|
||||
|
||||
/*
|
||||
* When run-time partition pruning is not enabled we can just mark all
|
||||
* subplans as valid; they must also all be initialized.
|
||||
*/
|
||||
mergestate->ms_valid_subplans = validsubplans =
|
||||
bms_add_range(NULL, 0, nplans - 1);
|
||||
mergestate->ms_prune_state = NULL;
|
||||
}
|
||||
|
||||
mergeplanstates = (PlanState **) palloc(nplans * sizeof(PlanState *));
|
||||
mergestate->mergeplans = mergeplanstates;
|
||||
mergestate->ms_nplans = nplans;
|
||||
|
||||
@ -101,26 +165,24 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* MergeAppend plans don't have expression contexts because they never
|
||||
* call ExecQual or ExecProject.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MergeAppend nodes do have Result slots, which hold pointers to tuples,
|
||||
* so we have to initialize them.
|
||||
*/
|
||||
ExecInitResultTupleSlotTL(estate, &mergestate->ps);
|
||||
|
||||
/*
|
||||
* call ExecInitNode on each of the plans to be executed and save the
|
||||
* results into the array "mergeplans".
|
||||
* call ExecInitNode on each of the valid plans to be executed and save
|
||||
* the results into the mergeplanstates array.
|
||||
*/
|
||||
i = 0;
|
||||
j = i = 0;
|
||||
foreach(lc, node->mergeplans)
|
||||
{
|
||||
Plan *initNode = (Plan *) lfirst(lc);
|
||||
if (bms_is_member(i, validsubplans))
|
||||
{
|
||||
Plan *initNode = (Plan *) lfirst(lc);
|
||||
|
||||
mergeplanstates[i] = ExecInitNode(initNode, estate, eflags);
|
||||
mergeplanstates[j++] = ExecInitNode(initNode, estate, eflags);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -178,11 +240,25 @@ ExecMergeAppend(PlanState *pstate)
|
||||
|
||||
if (!node->ms_initialized)
|
||||
{
|
||||
/* Nothing to do if all subplans were pruned */
|
||||
if (node->ms_noopscan)
|
||||
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
|
||||
/*
|
||||
* First time through: pull the first tuple from each subplan, and set
|
||||
* up the heap.
|
||||
* If we've yet to determine the valid subplans then do so now. If
|
||||
* run-time pruning is disabled then the valid subplans will always be
|
||||
* set to all subplans.
|
||||
*/
|
||||
for (i = 0; i < node->ms_nplans; i++)
|
||||
if (node->ms_valid_subplans == NULL)
|
||||
node->ms_valid_subplans =
|
||||
ExecFindMatchingSubPlans(node->ms_prune_state);
|
||||
|
||||
/*
|
||||
* First time through: pull the first tuple from each valid subplan,
|
||||
* and set up the heap.
|
||||
*/
|
||||
i = -1;
|
||||
while ((i = bms_next_member(node->ms_valid_subplans, i)) >= 0)
|
||||
{
|
||||
node->ms_slots[i] = ExecProcNode(node->mergeplans[i]);
|
||||
if (!TupIsNull(node->ms_slots[i]))
|
||||
@ -288,6 +364,12 @@ ExecEndMergeAppend(MergeAppendState *node)
|
||||
*/
|
||||
for (i = 0; i < nplans; i++)
|
||||
ExecEndNode(mergeplans[i]);
|
||||
|
||||
/*
|
||||
* release any resources associated with run-time pruning
|
||||
*/
|
||||
if (node->ms_prune_state)
|
||||
ExecDestroyPartitionPruneState(node->ms_prune_state);
|
||||
}
|
||||
|
||||
void
|
||||
@ -295,6 +377,19 @@ ExecReScanMergeAppend(MergeAppendState *node)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* If any PARAM_EXEC Params used in pruning expressions have changed, then
|
||||
* we'd better unset the valid subplans so that they are reselected for
|
||||
* the new parameter values.
|
||||
*/
|
||||
if (node->ms_prune_state &&
|
||||
bms_overlap(node->ps.chgParam,
|
||||
node->ms_prune_state->execparamids))
|
||||
{
|
||||
bms_free(node->ms_valid_subplans);
|
||||
node->ms_valid_subplans = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < node->ms_nplans; i++)
|
||||
{
|
||||
PlanState *subnode = node->mergeplans[i];
|
||||
|
Reference in New Issue
Block a user