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);