From 2616e2c0623d212d6a957f24b620d9ca6855023d Mon Sep 17 00:00:00 2001 From: Ashutosh Bapat Date: Thu, 22 Jun 2023 14:27:14 +0530 Subject: [PATCH 2/2] Avoid translating RestrictInfo repeatedly RestrictInfo to be applied to the child rels (including the child join rels) are obtained by translating RestrictInfo applicable to the parent rel. Since these translations are not tracked, the same RestrictInfo may get translated multiple times for the same parent and child pair. When using partitionwise join this can happen as many times as the number of possible join orders between the partitioned tables. Every translated RestrictInfo is stored in the top parent's RestrictInfo in a list. Every translated RestrictInfo contains a pointer to the top parent's RestrictInfo to track multilevel translations. RestrictInfo::required_relids is used as a key to search a given translation. adjust_appendrel_attrs_mutator() first looks up an existing translations when translating a RestrictInfo and creates a new one only when one doesn't exist. Ashutosh Bapat --- src/backend/optimizer/util/appendinfo.c | 43 ++++++++++++++++++++++- src/backend/optimizer/util/restrictinfo.c | 2 ++ src/include/nodes/pathnodes.h | 7 ++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c index f456b3b0a4..8931cf91a4 100644 --- a/src/backend/optimizer/util/appendinfo.c +++ b/src/backend/optimizer/util/appendinfo.c @@ -217,6 +217,7 @@ adjust_appendrel_attrs_mutator(Node *node, { AppendRelInfo **appinfos = context->appinfos; int nappinfos = context->nappinfos; + PlannerInfo *root = context->root; int cnt; if (node == NULL) @@ -445,7 +446,42 @@ adjust_appendrel_attrs_mutator(Node *node, if (IsA(node, RestrictInfo)) { RestrictInfo *oldinfo = (RestrictInfo *) node; - RestrictInfo *newinfo = makeNode(RestrictInfo); + Relids child_required_relids = adjust_child_relids(oldinfo->required_relids, + nappinfos, appinfos); + RestrictInfo *parent_rinfo; + ListCell *lc; + RestrictInfo *newinfo; + MemoryContext old_context; + + /* + * If the adjusted RestrictInfo already exists, use it otherwise create + * a new one. This avoids translating the same RestrictInfo again and + * again wasting memory especially in partitionwise joins. + */ + + if (bms_equal(child_required_relids, oldinfo->required_relids)) + return (Node *) oldinfo; + + /* + * Check if we already have the RestrictInfo for the given child in the + * topmost parent's RestrictInfo. + */ + parent_rinfo = oldinfo->parent_rinfo ? oldinfo->parent_rinfo : oldinfo; + foreach (lc, parent_rinfo->child_rinfos) + { + newinfo = lfirst(lc); + + if (bms_equal(newinfo->required_relids, child_required_relids)) + { + bms_free(child_required_relids); + return (Node *) newinfo; + } + } + bms_free(child_required_relids); + + /* Translate in a long lasting memory context. */ + old_context = MemoryContextSwitchTo(root->planner_cxt); + newinfo = makeNode(RestrictInfo); /* Copy all flat-copiable fields, notably including rinfo_serial */ memcpy(newinfo, oldinfo, sizeof(RestrictInfo)); @@ -491,6 +527,11 @@ adjust_appendrel_attrs_mutator(Node *node, newinfo->right_bucketsize = -1; newinfo->left_mcvfreq = -1; newinfo->right_mcvfreq = -1; + newinfo->parent_rinfo = parent_rinfo; + parent_rinfo->child_rinfos = lappend(parent_rinfo->child_rinfos, + newinfo); + + MemoryContextSwitchTo(old_context); return (Node *) newinfo; } diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index c1fbbb6bfe..fec8eeef58 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -246,6 +246,8 @@ make_restrictinfo_internal(PlannerInfo *root, restrictinfo->left_hasheqoperator = InvalidOid; restrictinfo->right_hasheqoperator = InvalidOid; + restrictinfo->child_rinfos = NIL; + restrictinfo->parent_rinfo = NULL; return restrictinfo; } diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index a1dc1d07e1..a9b2809f2c 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -2658,6 +2658,13 @@ typedef struct RestrictInfo /* hash equality operators used for memoize nodes, else InvalidOid */ Oid left_hasheqoperator pg_node_attr(equal_ignore); Oid right_hasheqoperator pg_node_attr(equal_ignore); + + /* Only one of these two can be set. */ + List *child_rinfos pg_node_attr(equal_ignore, copy_as(NIL)); /* RestrictInfos derived for children. */ + struct RestrictInfo *parent_rinfo pg_node_attr(equal_ignore, copy_as(NULL)); /* Parent restrictinfo this + * RestrictInf is derived from. + */ + } RestrictInfo; /* -- 2.25.1