0001-skip-tuple-routing-for-constant-partition-key.patch
application/octet-stream
Filename: 0001-skip-tuple-routing-for-constant-partition-key.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch 0001
Subject: skip-tuple-routing-for-constant-partition-key
| File | + | − |
|---|---|---|
| src/backend/access/common/tupconvert.c | 37 | 0 |
| src/backend/commands/copyfrom.c | 3 | 0 |
| src/backend/executor/execPartition.c | 79 | 5 |
| src/backend/executor/nodeModifyTable.c | 50 | 1 |
| src/include/access/tupconvert.h | 1 | 0 |
| src/include/nodes/execnodes.h | 9 | 0 |
From 6972ae859d2543225baf669363bfe6f8e70c0add Mon Sep 17 00:00:00 2001
From: houzj <houzj.fnst@cn.fujitsu.com>
Date: Mon, 17 May 2021 17:43:57 +0800
Subject: [PATCH] skip-tuple-routing-for-constant-partition-key
---
src/backend/access/common/tupconvert.c | 37 +++++++++++++++
src/backend/commands/copyfrom.c | 3 ++
src/backend/executor/execPartition.c | 84 ++++++++++++++++++++++++++++++++--
src/backend/executor/nodeModifyTable.c | 51 ++++++++++++++++++++-
src/include/access/tupconvert.h | 1 +
src/include/nodes/execnodes.h | 9 ++++
6 files changed, 179 insertions(+), 6 deletions(-)
diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c
index 64f5439..f22414f 100644
--- a/src/backend/access/common/tupconvert.c
+++ b/src/backend/access/common/tupconvert.c
@@ -278,6 +278,43 @@ execute_attr_map_cols(AttrMap *attrMap, Bitmapset *in_cols)
}
/*
+ * Perform conversion of bitmap of columns according to the map.
+ *
+ * Only convert normal user column.
+ *
+ * output column that does not correspond to any input column will
+ * still be set in bitmap.
+ */
+Bitmapset *
+execute_attr_map_cols_with_null(AttrMap *attrMap, Bitmapset *in_cols)
+{
+ Bitmapset *out_cols;
+ int out_attnum;
+
+ /* fast path for the common trivial case */
+ if (in_cols == NULL)
+ return NULL;
+
+ out_cols = NULL;
+
+ for (out_attnum = 1;
+ out_attnum <= attrMap->maplen;
+ out_attnum++)
+ {
+ int in_attnum;
+
+ in_attnum = attrMap->attnums[out_attnum - 1];
+
+ if (in_attnum == 0 ||
+ bms_is_member(in_attnum, in_cols))
+ out_cols = bms_add_member(out_cols, out_attnum);
+ }
+
+ return out_cols;
+}
+
+
+/*
* Free a TupleConversionMap structure.
*/
void
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 40a54ad..ea62cfa 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -670,6 +670,9 @@ CopyFrom(CopyFromState cstate)
mtstate->mt_nrels = 1;
mtstate->resultRelInfo = resultRelInfo;
mtstate->rootResultRelInfo = resultRelInfo;
+ mtstate->const_bms = NULL;
+ mtstate->cache_routed_rel = false;
+ mtstate->targetpartrel = NULL;
if (resultRelInfo->ri_FdwRoutine != NULL &&
resultRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL)
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 606c920..dca6799 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -24,6 +24,7 @@
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
+#include "optimizer/optimizer.h"
#include "partitioning/partbounds.h"
#include "partitioning/partdesc.h"
#include "partitioning/partprune.h"
@@ -191,7 +192,7 @@ static void find_matching_subplans_recurse(PartitionPruningData *prunedata,
PartitionedRelPruningData *pprune,
bool initial_prune,
Bitmapset **validsubplans);
-
+static bool ExecSimplifyTupleRouting(PartitionDispatch pd, Bitmapset *constcols);
/*
* ExecSetupPartitionTupleRouting - sets up information needed during
@@ -271,6 +272,15 @@ ExecFindPartition(ModifyTableState *mtstate,
TupleTableSlot *myslot = NULL;
MemoryContext oldcxt;
ResultRelInfo *rri = NULL;
+ bool need_tuple_routing;
+ Bitmapset *const_bms = mtstate->const_bms;
+ Bitmapset *root_const_bms = mtstate->const_bms;
+
+ need_tuple_routing = !(RelationGetRelid(rootResultRelInfo->ri_RelationDesc) ==
+ RelationGetRelid(mtstate->rootResultRelInfo->ri_RelationDesc));
+
+ if (mtstate->targetpartrel != NULL && !need_tuple_routing)
+ return mtstate->targetpartrel;
/* use per-tuple context here to avoid leaking memory */
oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
@@ -327,6 +337,11 @@ ExecFindPartition(ModifyTableState *mtstate,
errtable(rel)));
}
+ /* Check if we can skip tuple routing next time */
+ if (mtstate->cache_routed_rel)
+ mtstate->cache_routed_rel = ExecSimplifyTupleRouting(dispatch,
+ const_bms);
+
is_leaf = partdesc->is_leaf[partidx];
if (is_leaf)
{
@@ -415,8 +430,8 @@ ExecFindPartition(ModifyTableState *mtstate,
}
/*
- * Convert the tuple to the new parent's layout, if different from
- * the previous parent.
+ * Convert the tuple and constant value bitmap to the new parent's
+ * layout, if different from the previous parent.
*/
if (dispatch->tupslot)
{
@@ -424,6 +439,10 @@ ExecFindPartition(ModifyTableState *mtstate,
TupleTableSlot *tempslot = myslot;
myslot = dispatch->tupslot;
+
+ if (mtstate->cache_routed_rel)
+ const_bms = execute_attr_map_cols_with_null(map, const_bms);
+
slot = execute_attr_map_slot(map, slot, myslot);
if (tempslot != NULL)
@@ -450,24 +469,43 @@ ExecFindPartition(ModifyTableState *mtstate,
*
* Note that we have a map to convert from root to current
* partition, but not from immediate parent to current partition.
- * So if we have to convert, do it from the root slot; if not, use
- * the root slot as-is.
+ * So if we have to convert, do it from the root slot and constant
+ * value bitmap; if not, use the root slot as-is.
*/
if (is_leaf)
{
TupleConversionMap *map = rri->ri_RootToPartitionMap;
if (map)
+ {
+ if (mtstate->cache_routed_rel)
+ const_bms = execute_attr_map_cols_with_null(map->attrMap,
+ const_bms);
+
slot = execute_attr_map_slot(map->attrMap, rootslot,
rri->ri_PartitionTupleSlot);
+ }
else
+ {
+ const_bms = root_const_bms;
slot = rootslot;
+ }
}
ExecPartitionCheck(rri, slot, estate, true);
}
}
+ /*
+ * If all of the columns used in partition key are constant, cache the
+ * target partition if first time reach here.
+ */
+ if (mtstate->cache_routed_rel)
+ {
+ mtstate->cache_routed_rel = false;
+ mtstate->targetpartrel = rri;
+ }
+
/* Release the tuple in the lowest parent's dedicated slot. */
if (myslot != NULL)
ExecClearTuple(myslot);
@@ -1165,6 +1203,42 @@ ExecCleanupTupleRouting(ModifyTableState *mtstate,
}
}
+/*
+ * Check whether all of the columns used in partition key are
+ * const value
+ */
+static bool
+ExecSimplifyTupleRouting(PartitionDispatch pd,
+ Bitmapset *constcols)
+{
+ int i;
+ List *expr_vars;
+ ListCell *lc;
+
+ if (constcols == NULL)
+ return false;
+
+ /* Check plain columns */
+ for (i = 0; i < pd->key->partnatts; i++)
+ {
+ AttrNumber keycol = pd->key->partattrs[i];
+ if (keycol != 0 && !bms_is_member(keycol, constcols))
+ return false;
+ }
+
+ /* Check columns in partition expression */
+ expr_vars = pull_var_clause((Node *) pd->key->partexprs, 0);
+ foreach(lc, expr_vars)
+ {
+ Var *var = lfirst(lc);
+
+ if (var->varno == 1 && !bms_is_member(var->varattno, constcols))
+ return false;
+ }
+
+ return true;
+}
+
/* ----------------
* FormPartitionKeyDatum
* Construct values[] and isnull[] arrays for the partition key
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 0816027..5d7dcb2 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1445,7 +1445,11 @@ ExecCrossPartitionUpdate(ModifyTableState *mtstate,
/* Initialize tuple routing info if not already done. */
if (mtstate->mt_partition_tuple_routing == NULL)
{
+ ListCell *lc, *lc2;
+ List *updateColnos;
+ List *targetlist;
Relation rootRel = mtstate->rootResultRelInfo->ri_RelationDesc;
+ ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
MemoryContext oldcxt;
/* Things built here have to last for the query duration. */
@@ -1454,6 +1458,22 @@ ExecCrossPartitionUpdate(ModifyTableState *mtstate,
mtstate->mt_partition_tuple_routing =
ExecSetupPartitionTupleRouting(estate, rootRel);
+ /* Initialize constant value bitmapset */
+ Assert(mtstate->const_bms == NULL);
+ mtstate->cache_routed_rel = true;
+ updateColnos = (List *) list_nth(node->updateColnosLists,
+ resultRelInfo - mtstate->resultRelInfo);
+
+ targetlist = outerPlan(node)->targetlist;
+ forboth(lc, targetlist, lc2, updateColnos)
+ {
+ TargetEntry *tle = lfirst_node(TargetEntry, lc);
+ AttrNumber targetattnum = lfirst_int(lc2);
+ if (!tle->resjunk && IsA(tle->expr, Const))
+ mtstate->const_bms = bms_add_member(mtstate->const_bms,
+ targetattnum);
+ }
+
/*
* Before a partition's tuple can be re-routed, it must first be
* converted to the root's format, so we'll need a slot for storing
@@ -1532,10 +1552,17 @@ ExecCrossPartitionUpdate(ModifyTableState *mtstate,
*/
tupconv_map = ExecGetChildToRootMap(resultRelInfo);
if (tupconv_map != NULL)
- slot = execute_attr_map_slot(tupconv_map->attrMap,
+ {
+ AttrMap *attrMap = tupconv_map->attrMap;
+ slot = execute_attr_map_slot(attrMap,
slot,
mtstate->mt_root_tuple_slot);
+ if (mtstate->cache_routed_rel)
+ mtstate->const_bms = execute_attr_map_cols_with_null(attrMap,
+ mtstate->const_bms);
+ }
+
/* Tuple routing starts from the root table. */
*inserted_tuple = ExecInsert(mtstate, mtstate->rootResultRelInfo, slot,
planSlot, estate, canSetTag);
@@ -2874,6 +2901,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* Get the root target relation */
rel = mtstate->rootResultRelInfo->ri_RelationDesc;
+ mtstate->cache_routed_rel = false;
+ mtstate->const_bms = NULL;
+ mtstate->targetpartrel = NULL;
+
/*
* Build state for tuple routing if it's a partitioned INSERT. An UPDATE
* might need this too, but only if it actually moves tuples between
@@ -2881,9 +2912,27 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
*/
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
operation == CMD_INSERT)
+ {
mtstate->mt_partition_tuple_routing =
ExecSetupPartitionTupleRouting(estate, rel);
+ mtstate->cache_routed_rel = true;
+
+ /*
+ * Build the constant bitmap for tuple routing simplification if
+ * it's a partitioned INSERT. Cross partition UPDATE will build it
+ * in ExecCrossPartitionUpdate.
+ */
+ i = 1;
+ foreach(l, subplan->targetlist)
+ {
+ TargetEntry *tc = (TargetEntry *) lfirst(l);
+ if (!tc->resjunk && IsA(tc->expr, Const))
+ mtstate->const_bms = bms_add_member(mtstate->const_bms, i);
+ i++;
+ }
+ }
+
/*
* Initialize any WITH CHECK OPTION constraints if needed.
*/
diff --git a/src/include/access/tupconvert.h b/src/include/access/tupconvert.h
index a2cc4b3..ea8eeac 100644
--- a/src/include/access/tupconvert.h
+++ b/src/include/access/tupconvert.h
@@ -45,6 +45,7 @@ extern TupleTableSlot *execute_attr_map_slot(AttrMap *attrMap,
TupleTableSlot *in_slot,
TupleTableSlot *out_slot);
extern Bitmapset *execute_attr_map_cols(AttrMap *attrMap, Bitmapset *inbitmap);
+extern Bitmapset *execute_attr_map_cols_with_null(AttrMap *attrMap, Bitmapset *inbitmap);
extern void free_conversion_map(TupleConversionMap *map);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 7795a69..5ba392b 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1213,6 +1213,15 @@ typedef struct ModifyTableState
HTAB *mt_resultOidHash; /* optional hash table to speed lookups */
/*
+ * Cached target partition if all the columns in partition key are
+ * constant, otherwise NULL
+ */
+ ResultRelInfo *targetpartrel;
+ Bitmapset *const_bms; /* column numbers of constant value */
+ bool cache_routed_rel; /* do we need to cache the target
+ * partition after tuple routing */
+
+ /*
* Slot for storing tuples in the root partitioned table's rowtype during
* an UPDATE of a partitioned table.
*/
--
2.7.2.windows.1