pg.ddx.io pgsql-hackers@postgresql.org mailing list archive
help / color / mirror / Atom feed From: Alvaro Herrera <alvherre@alvh.no-ip.org>
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
Cc: David Rowley <david.rowley@2ndquadrant.com>
Cc: Robert Haas <robertmhaas@gmail.com>
Cc: Amit Langote <amitlangote09@gmail.com>
Cc: Jesper Pedersen <jesper.pedersen@redhat.com>
Cc: Rajkumar Raghuwanshi <rajkumar.raghuwanshi@enterprisedb.com>
Cc: Beena Emerson <memissemerson@gmail.com>
Cc: amul sul <sulamul@gmail.com>
Cc: pgsql-hackers@postgresql.org <pgsql-hackers@postgresql.org>
Cc: Dilip Kumar <dilipbalaut@gmail.com>
Subject: Re: [HACKERS] Runtime Partition Pruning
Date: Tue, 24 Apr 2018 11:19:04 -0300
Message-ID: <20180424141904.73tydqgb35lhjcsb@alvherre.pgsql> (raw )
In-Reply-To: <be61173a-b5a1-3993-27f0-4116e40d9621@lab.ntt.co.jp >
Amit Langote wrote:
> That's neat! Definitely agree that we should call ExecInitExpr just once
> here. The patch looks good too, except the long line.
How about this as a small tweak? Determine the array index using a
macro, which serves as documentation.
--
Álvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 135740cd17e8c05f36a3b91b3af29515df6a2d3b Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 19 Apr 2018 11:51:16 +1200
Subject: [PATCH v3] Initialize ExprStates once in run-time partition pruning
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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 | 35 +++++++++++++++++++++++++++++++++++
src/backend/partitioning/partprune.c | 27 +++++++++++++++++----------
src/include/partitioning/partprune.h | 9 +++++++++
3 files changed, 61 insertions(+), 10 deletions(-)
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index f7bbb804aa..f7418f64b1 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -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);
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index f8844ef2eb..62159477c1 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -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;
diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h
index a5568abce6..c9fe95dc30 100644
--- a/src/include/partitioning/partprune.h
+++ b/src/include/partitioning/partprune.h
@@ -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);
--
2.11.0
Attachments:
[text/plain] v3-0001-Initialize-ExprStates-once-in-run-time-partition-.patch (6.4K, ../20180424141904.73tydqgb35lhjcsb@alvherre.pgsql/2-v3-0001-Initialize-ExprStates-once-in-run-time-partition-.patch)
download | inline diff:
From 135740cd17e8c05f36a3b91b3af29515df6a2d3b Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Thu, 19 Apr 2018 11:51:16 +1200
Subject: [PATCH v3] Initialize ExprStates once in run-time partition pruning
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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 | 35 +++++++++++++++++++++++++++++++++++
src/backend/partitioning/partprune.c | 27 +++++++++++++++++----------
src/include/partitioning/partprune.h | 9 +++++++++
3 files changed, 61 insertions(+), 10 deletions(-)
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index f7bbb804aa..f7418f64b1 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -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);
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index f8844ef2eb..62159477c1 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -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;
diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h
index a5568abce6..c9fe95dc30 100644
--- a/src/include/partitioning/partprune.h
+++ b/src/include/partitioning/partprune.h
@@ -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);
--
2.11.0
view thread (186+ messages) latest in thread
Message-ID: <20180424141904.73tydqgb35lhjcsb@alvherre.pgsql>
Permalink: ../20180424141904.73tydqgb35lhjcsb@alvherre.pgsql/
Also on: postgresql.org/message-id/20180424141904.73tydqgb35lhjcsb@alvherre.pgsql
copy link · copy postgr.es · copy git am
reply Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: alvherre@alvh.no-ip.org, Langote_Amit_f8@lab.ntt.co.jp, david.rowley@2ndquadrant.com, robertmhaas@gmail.com, amitlangote09@gmail.com, jesper.pedersen@redhat.com, rajkumar.raghuwanshi@enterprisedb.com, memissemerson@gmail.com, sulamul@gmail.com, dilipbalaut@gmail.com
Subject: Re: [HACKERS] Runtime Partition Pruning
In-Reply-To: <20180424141904.73tydqgb35lhjcsb@alvherre.pgsql>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox