]> granicus.if.org Git - postgresql/commitdiff
Initialize ExprStates once in run-time partition pruning
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 24 Apr 2018 17:03:10 +0000 (14:03 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 24 Apr 2018 17:03:10 +0000 (14:03 -0300)
Instead of doing ExecInitExpr every time a Param needs to be evaluated
in run-time partition pruning, do it once during run-time pruning
set-up and cache the exprstate in PartitionPruneContext, saving a lot of
work.

Author: David Rowley
Reviewed-by: Amit Langote, Álvaro Herrera
Discussion: https://postgr.es/m/CAKJS1f8-x+q-90QAPDu_okhQBV4DPEtPz8CJ=m0940GyT4DA4w@mail.gmail.com

src/backend/executor/execPartition.c
src/backend/partitioning/partprune.c
src/include/partitioning/partprune.h

index f7bbb804aae7c6a31fa49a337b9a023d681dfc1c..f7418f64b18c1b3176d6a47712c3969b538c7168 100644 (file)
@@ -1442,7 +1442,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);
@@ -1465,6 +1467,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;
@@ -1476,6 +1479,38 @@ 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;
+
+                       /* not needed for other step kinds */
+                       if (!IsA(step, PartitionPruneStepOp))
+                               continue;
+
+                       Assert(list_length(step->exprs) <= partnatts);
+
+                       keyno = 0;
+                       foreach(lc3, step->exprs)
+                       {
+                               Expr       *expr = (Expr *) lfirst(lc3);
+                               int                     stateidx;
+
+                               /* not needed for Consts */
+                               if (!IsA(expr, Const))
+                               {
+                                       stateidx = PruneCxtStateIdx(partnatts,
+                                                                                               step->step.step_id, keyno);
+                                       context->exprstates[stateidx] =
+                                               ExecInitExpr(expr, context->planstate);
+                               }
+                               keyno++;
+                       }
+               }
 
                pprune->pruning_steps = pinfo->pruning_steps;
                pprune->extparams = bms_copy(pinfo->extparams);
index f8844ef2eb66ba80a42767af7aa5c663348053c7..62159477c1e5c1c17eb89efe71c64c471ed6ceea 100644 (file)
@@ -169,7 +169,7 @@ 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);
+                                               Expr *expr, int stateidx, Datum *value);
 
 /*
  * make_partition_pruneinfo
@@ -444,6 +444,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);
@@ -2788,10 +2789,13 @@ perform_pruning_base_step(PartitionPruneContext *context,
                if (lc1 != NULL)
                {
                        Expr       *expr;
+                       int                     stateidx;
                        Datum           datum;
 
                        expr = lfirst(lc1);
-                       if (partkey_datum_from_expr(context, expr, &datum))
+                       stateidx = PruneCxtStateIdx(context->partnatts,
+                                                                               opstep->step.step_id, keyno);
+                       if (partkey_datum_from_expr(context, expr, stateidx, &datum))
                        {
                                Oid                     cmpfn;
 
@@ -3025,12 +3029,15 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
 
 /*
  * partkey_datum_from_expr
- *             Evaluate 'expr', set *value to the resulting Datum. Return true if
- *             evaluation was possible, otherwise false.
+ *             Evaluate expression for potential partition pruning
+ *
+ * Evaluate 'expr', whose ExprState is stateidx of the context exprstate
+ * array; set *value to the resulting Datum.  Return true if evaluation was
+ * possible, otherwise false.
  */
 static bool
 partkey_datum_from_expr(PartitionPruneContext *context,
-                                               Expr *expr, Datum *value)
+                                               Expr *expr, int stateidx, Datum *value)
 {
        switch (nodeTag(expr))
        {
@@ -3048,18 +3055,18 @@ partkey_datum_from_expr(PartitionPruneContext *context,
                                bms_is_member(((Param *) expr)->paramid, context->safeparams))
                        {
                                ExprState  *exprstate;
+                               ExprContext *ectx;
                                bool            isNull;
 
-                               exprstate = ExecInitExpr(expr, context->planstate);
-
-                               *value = ExecEvalExprSwitchContext(exprstate,
-                                                                                                  context->planstate->ps_ExprContext,
-                                                                                                  &isNull);
+                               exprstate = context->exprstates[stateidx];
+                               ectx = context->planstate->ps_ExprContext;
+                               *value = ExecEvalExprSwitchContext(exprstate, ectx, &isNull);
                                if (isNull)
                                        return false;
 
                                return true;
                        }
+                       break;
 
                default:
                        break;
index a5568abce653e1529f0fa90a76c23cc0b96df7f8..c9fe95dc30c17d16c0593200d4fc0edae802c5ff 100644 (file)
@@ -50,8 +50,17 @@ typedef struct PartitionPruneContext
         * are not safe to use until the executor is running.
         */
        Bitmapset  *safeparams;
+
+       /*
+        * Array of ExprStates, indexed as per PruneCtxStateIdx; one for each
+        * partkey in each pruning step.  Allocated if planstate is non-NULL,
+        * otherwise NULL.
+        */
+       ExprState **exprstates;
 } PartitionPruneContext;
 
+#define PruneCxtStateIdx(partnatts, step_id, keyno) \
+       ((partnatts) * (step_id) + (keyno))
 
 extern List *make_partition_pruneinfo(PlannerInfo *root, List *partition_rels,
                                                 List *subpaths, List *prunequal);