diff options
Diffstat (limited to 'src/backend/partitioning/partprune.c')
-rw-r--r-- | src/backend/partitioning/partprune.c | 211 |
1 files changed, 176 insertions, 35 deletions
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index bfacc2ce297..752810d0e42 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -112,6 +112,11 @@ typedef struct PruneStepResult } PruneStepResult; +static List *make_partitionedrel_pruneinfo(PlannerInfo *root, + RelOptInfo *parentrel, + int *relid_subplan_map, + List *partitioned_rels, List *prunequal, + Bitmapset **matchedsubplans); static List *gen_partprune_steps(RelOptInfo *rel, List *clauses, bool *contradictory); static List *gen_partprune_steps_internal(GeneratePruningStepsContext *context, @@ -160,7 +165,7 @@ static PruneStepResult *get_matching_range_bounds(PartitionPruneContext *context FmgrInfo *partsupfunc, Bitmapset *nullkeys); static Bitmapset *pull_exec_paramids(Expr *expr); static bool pull_exec_paramids_walker(Node *node, Bitmapset **context); -static bool analyze_partkey_exprs(PartitionPruneInfo *pinfo, List *steps, +static bool analyze_partkey_exprs(PartitionedRelPruneInfo *pinfo, List *steps, int partnatts); static PruneStepResult *perform_pruning_base_step(PartitionPruneContext *context, PartitionPruneStepOp *opstep); @@ -176,38 +181,43 @@ static bool partkey_datum_from_expr(PartitionPruneContext *context, /* * make_partition_pruneinfo - * Build List of PartitionPruneInfos, one for each partitioned rel. - * These can be used in the executor to allow additional partition - * pruning to take place. + * 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. * - * Here we generate partition pruning steps for 'prunequal' and also build a - * data structure which allows mapping of partition indexes into 'subpaths' - * indexes. + * 'parentrel' is the RelOptInfo for an appendrel, and 'subpaths' is the list + * of scan paths for its child rels. * - * If no non-Const expressions are being compared to the partition key in any - * of the 'partitioned_rels', then we return NIL to indicate no run-time - * pruning should be performed. Run-time pruning would be useless, since the - * pruning done during planning will have pruned everything that can be. + * 'partitioned_rels' is a List containing Lists of relids of partitioned + * tables (a/k/a non-leaf partitions) that are parents of some of the child + * rels. Here we attempt to populate the PartitionPruneInfo by adding a + * 'prune_infos' item for each sublist in the 'partitioned_rels' list. + * However, some of the sets of partitioned relations may not require any + * run-time pruning. In these cases we'll simply not include a 'prune_infos' + * item for that set and instead we'll add all the subplans which belong to + * that set into the PartitionPruneInfo's 'other_subplans' field. Callers + * will likely never want to prune subplans which are mentioned in this field. + * + * 'prunequal' is a list of potential pruning quals. */ -List * -make_partition_pruneinfo(PlannerInfo *root, List *partitioned_rels, - List *subpaths, List *prunequal) +PartitionPruneInfo * +make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, + List *subpaths, List *partitioned_rels, + List *prunequal) { - RelOptInfo *targetpart = NULL; - List *pinfolist = NIL; - bool doruntimeprune = false; + PartitionPruneInfo *pruneinfo; + Bitmapset *allmatchedsubplans = NULL; int *relid_subplan_map; - int *relid_subpart_map; ListCell *lc; + List *prunerelinfos; int i; /* - * Construct two temporary arrays to map from planner relids to subplan - * and sub-partition indexes. For convenience, we use 1-based indexes - * here, so that zero can represent an un-filled array entry. + * Construct a temporary array to map from planner relids to subplan + * indexes. For convenience, we use 1-based indexes here, so that zero + * can represent an un-filled array entry. */ relid_subplan_map = palloc0(sizeof(int) * root->simple_rel_array_size); - relid_subpart_map = palloc0(sizeof(int) * root->simple_rel_array_size); /* * relid_subplan_map maps relid of a leaf partition to the index in @@ -227,10 +237,107 @@ make_partition_pruneinfo(PlannerInfo *root, List *partitioned_rels, relid_subplan_map[pathrel->relid] = i++; } + /* We now build a PartitionedRelPruneInfo for each partitioned rel. */ + prunerelinfos = NIL; + foreach(lc, partitioned_rels) + { + List *rels = (List *) lfirst(lc); + List *pinfolist; + Bitmapset *matchedsubplans = NULL; + + pinfolist = make_partitionedrel_pruneinfo(root, parentrel, + relid_subplan_map, + rels, prunequal, + &matchedsubplans); + + /* When pruning is possible, record the matched subplans */ + if (pinfolist != NIL) + { + prunerelinfos = lappend(prunerelinfos, pinfolist); + allmatchedsubplans = bms_join(matchedsubplans, + allmatchedsubplans); + } + } + + pfree(relid_subplan_map); + + /* + * If none of the partition hierarchies had any useful run-time pruning + * quals, then we can just not bother with run-time pruning. + */ + if (prunerelinfos == NIL) + return NULL; + + /* Else build the result data structure */ + pruneinfo = makeNode(PartitionPruneInfo); + pruneinfo->prune_infos = prunerelinfos; + + /* + * Some subplans may not belong to any of the listed partitioned rels. + * This can happen for UNION ALL queries which include a non-partitioned + * table, or when some of the hierarchies aren't run-time prunable. Build + * a bitmapset of the indexes of all such subplans, so that the executor + * can identify which subplans should never be pruned. + */ + if (bms_num_members(allmatchedsubplans) < list_length(subpaths)) + { + Bitmapset *other_subplans; + + /* Create the complement of allmatchedsubplans */ + other_subplans = bms_add_range(NULL, 0, list_length(subpaths) - 1); + other_subplans = bms_del_members(other_subplans, allmatchedsubplans); + + pruneinfo->other_subplans = other_subplans; + } + else + pruneinfo->other_subplans = NULL; + + return pruneinfo; +} + +/* + * make_partitionedrel_pruneinfo + * Build a List of PartitionedRelPruneInfos, one for each partitioned + * rel. These can be used in the executor to allow additional partition + * pruning to take place. + * + * Here we generate partition pruning steps for 'prunequal' and also build a + * data structure which allows mapping of partition indexes into 'subpaths' + * indexes. + * + * If no non-Const expressions are being compared to the partition key in any + * of the 'partitioned_rels', then we return NIL to indicate no run-time + * pruning should be performed. Run-time pruning would be useless since the + * pruning done during planning will have pruned everything that can be. + * + * On non-NIL return, 'matchedsubplans' is set to the subplan indexes which + * were matched to this partition hierarchy. + */ +static List * +make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, + int *relid_subplan_map, + List *partitioned_rels, List *prunequal, + Bitmapset **matchedsubplans) +{ + RelOptInfo *targetpart = NULL; + List *pinfolist = NIL; + bool doruntimeprune = false; + int *relid_subpart_map; + Bitmapset *subplansfound = NULL; + ListCell *lc; + int i; + + /* + * Construct a temporary array to map from planner relids to index of the + * partitioned_rel. For convenience, we use 1-based indexes here, so that + * zero can represent an un-filled array entry. + */ + relid_subpart_map = palloc0(sizeof(int) * root->simple_rel_array_size); + /* * relid_subpart_map maps relid of a non-leaf partition to the index in * 'partitioned_rels' of that rel (which will also be the index in the - * returned PartitionPruneInfo list of the info for that partition). + * returned PartitionedRelPruneInfo list of the info for that partition). */ i = 1; foreach(lc, partitioned_rels) @@ -246,12 +353,12 @@ make_partition_pruneinfo(PlannerInfo *root, List *partitioned_rels, relid_subpart_map[rti] = i++; } - /* We now build a PartitionPruneInfo for each partitioned rel */ + /* We now build a PartitionedRelPruneInfo for each partitioned rel */ foreach(lc, partitioned_rels) { Index rti = lfirst_int(lc); RelOptInfo *subpart = find_base_rel(root, rti); - PartitionPruneInfo *pinfo; + PartitionedRelPruneInfo *pinfo; RangeTblEntry *rte; Bitmapset *present_parts; int nparts = subpart->nparts; @@ -263,12 +370,35 @@ make_partition_pruneinfo(PlannerInfo *root, List *partitioned_rels, bool contradictory; /* - * The first item in the list is the target partitioned relation. The - * quals belong to this relation, so require no translation. + * The first item in the list is the target partitioned relation. */ if (!targetpart) { targetpart = subpart; + + /* + * The prunequal is presented to us as a qual for 'parentrel'. + * Frequently this rel is the same as targetpart, so we can skip + * an adjust_appendrel_attrs step. But it might not be, and then + * we have to translate. We update the prunequal parameter here, + * because in later iterations of the loop for child partitions, + * we want to translate from parent to child variables. + */ + if (parentrel != subpart) + { + int nappinfos; + AppendRelInfo **appinfos = find_appinfos_by_relids(root, + subpart->relids, + &nappinfos); + + prunequal = (List *) adjust_appendrel_attrs(root, (Node *) + prunequal, + nappinfos, + appinfos); + + pfree(appinfos); + } + partprunequal = prunequal; } else @@ -320,13 +450,20 @@ make_partition_pruneinfo(PlannerInfo *root, List *partitioned_rels, subplan_map[i] = subplanidx; subpart_map[i] = subpartidx; - if (subplanidx >= 0 || subpartidx >= 0) + if (subplanidx >= 0) + { + present_parts = bms_add_member(present_parts, i); + + /* Record finding this subplan */ + subplansfound = bms_add_member(subplansfound, subplanidx); + } + else if (subpartidx >= 0) present_parts = bms_add_member(present_parts, i); } rte = root->simple_rte_array[subpart->relid]; - pinfo = makeNode(PartitionPruneInfo); + pinfo = makeNode(PartitionedRelPruneInfo); pinfo->reloid = rte->relid; pinfo->pruning_steps = pruning_steps; pinfo->present_parts = present_parts; @@ -341,14 +478,17 @@ make_partition_pruneinfo(PlannerInfo *root, List *partitioned_rels, pinfolist = lappend(pinfolist, pinfo); } - pfree(relid_subplan_map); pfree(relid_subpart_map); - if (doruntimeprune) - return pinfolist; + if (!doruntimeprune) + { + /* No run-time pruning required. */ + return NIL; + } + + *matchedsubplans = subplansfound; - /* No run-time pruning required. */ - return NIL; + return pinfolist; } /* @@ -2772,7 +2912,8 @@ pull_exec_paramids_walker(Node *node, Bitmapset **context) * level. Also fills fields of *pinfo to record how to process each step. */ static bool -analyze_partkey_exprs(PartitionPruneInfo *pinfo, List *steps, int partnatts) +analyze_partkey_exprs(PartitionedRelPruneInfo *pinfo, List *steps, + int partnatts) { bool doruntimeprune = false; ListCell *lc; |