From 5a989e94e8d7e50a331740f7e7d2ccffed4e7391 Mon Sep 17 00:00:00 2001 From: "dgrowley@gmail.com" Date: Thu, 19 Apr 2018 11:51:16 +1200 Subject: [PATCH] Initialize expr states once in run-time partition pruning Previously ExecInitExpr was called every time a Param needed to be evaulated during run-time partition pruning. This meant additional memory allocations were made. Here we change things so we now call this function just once during the setup of run-time pruning. We cache the result in PartitionPruneContext so that it can be re-used each time pruning is invoked. --- src/backend/executor/execPartition.c | 31 +++++++++++++++++++++++++++++++ src/backend/partitioning/partprune.c | 17 ++++++++++++----- src/include/partitioning/partprune.h | 6 ++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 23a74bc3d9..5e4e24683c 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -1459,7 +1459,9 @@ ExecSetupPartitionPruneState(PlanState *planstate, List *partitionpruneinfo) PartitionDesc partdesc; Relation rel; PartitionKey partkey; + ListCell *lc2; int partnatts; + int n_steps; pprune->present_parts = bms_copy(pinfo->present_parts); pprune->subnode_map = palloc(sizeof(int) * pinfo->nparts); @@ -1482,6 +1484,7 @@ ExecSetupPartitionPruneState(PlanState *planstate, List *partitionpruneinfo) partkey = RelationGetPartitionKey(rel); partdesc = RelationGetPartitionDesc(rel); + n_steps = list_length(pinfo->pruning_steps); context->strategy = partkey->strategy; context->partnatts = partnatts = partkey->partnatts; @@ -1493,6 +1496,34 @@ ExecSetupPartitionPruneState(PlanState *planstate, List *partitionpruneinfo) context->boundinfo = partition_bounds_copy(partdesc->boundinfo, partkey); context->planstate = planstate; context->safeparams = NULL; /* empty for now */ + context->exprstates = palloc0(sizeof(ExprState *) * n_steps * partnatts); + + /* Initialize expression states for each expression */ + foreach(lc2, pinfo->pruning_steps) + { + PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc2); + ListCell *lc3; + int keyno; + + if (!IsA(step, PartitionPruneStepOp)) + continue; + + Assert(list_length(step->exprs) <= partnatts); + + keyno = 0; + foreach(lc3, step->exprs) + { + Expr *expr = (Expr *) lfirst(lc3); + + /* + * partkey_datum_from_expr does not need an expression state + * to evaluate a Const. + */ + if (!IsA(expr, Const)) + context->exprstates[step->step.step_id * partnatts + keyno] = ExecInitExpr(expr, context->planstate); + keyno++; + } + } pprune->pruning_steps = pinfo->pruning_steps; pprune->extparams = bms_copy(pinfo->extparams); diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 7666c6c412..f688357fe4 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -169,7 +169,8 @@ static PruneStepResult *perform_pruning_combine_step(PartitionPruneContext *cont static bool match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey, Expr **outconst); static bool partkey_datum_from_expr(PartitionPruneContext *context, - Expr *expr, Datum *value); + int step_id, int keyno, int partnatts, Expr *expr, + Datum *value); /* * make_partition_pruneinfo @@ -444,6 +445,7 @@ prune_append_rel_partitions(RelOptInfo *rel) /* Not valid when being called from the planner */ context.planstate = NULL; context.safeparams = NULL; + context.exprstates = NULL; /* Actual pruning happens here. */ partindexes = get_matching_partitions(&context, pruning_steps); @@ -2785,7 +2787,8 @@ perform_pruning_base_step(PartitionPruneContext *context, Datum datum; expr = lfirst(lc1); - if (partkey_datum_from_expr(context, expr, &datum)) + if (partkey_datum_from_expr(context, opstep->step.step_id, keyno, + context->partnatts, expr, &datum)) { Oid cmpfn; @@ -3023,8 +3026,8 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey, * evaluation was possible, otherwise false. */ static bool -partkey_datum_from_expr(PartitionPruneContext *context, - Expr *expr, Datum *value) +partkey_datum_from_expr(PartitionPruneContext * context, int step_id, + int keyno, int partnatts, Expr *expr, Datum *value) { switch (nodeTag(expr)) { @@ -3044,7 +3047,11 @@ partkey_datum_from_expr(PartitionPruneContext *context, ExprState *exprstate; bool isNull; - exprstate = ExecInitExpr(expr, context->planstate); + Assert(context->exprstates); + + exprstate = context->exprstates[step_id * partnatts + keyno]; + + Assert(exprstate); *value = ExecEvalExprSwitchContext(exprstate, context->planstate->ps_ExprContext, diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h index a5568abce6..31a4592397 100644 --- a/src/include/partitioning/partprune.h +++ b/src/include/partitioning/partprune.h @@ -50,6 +50,12 @@ typedef struct PartitionPruneContext * are not safe to use until the executor is running. */ Bitmapset *safeparams; + + /* + * Array of ExprStates, one for each partkey in each pruning step. Must + * be allocated if planstate is non-NULL, otherwise can be NULL. + */ + ExprState **exprstates; } PartitionPruneContext; -- 2.16.2.windows.1