summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmit Langote2024-03-25 03:02:40 +0000
committerAmit Langote2024-03-25 09:06:46 +0000
commit5278d0a2e870c61f9374a7796b90e6f9f6a73638 (patch)
tree065299c04b8ad160394bf832a33dcfe53d226617
parent619bc23a1a2f3750ac3668fe5a7564bc51e01684 (diff)
Reduce memory used by partitionwise joins
Specifically, this commit reduces the memory consumed by the SpecialJoinInfos that are allocated for child joins in try_partitionwise_join() by freeing them at the end of creating paths for each child join. A SpecialJoinInfo allocated for a given child join is a copy of the parent join's SpecialJoinInfo, which contains the translated copies of the various Relids bitmapsets and semi_rhs_exprs, which is a List of Nodes. The newly added freeing step frees the struct itself and the various bitmapsets, but not semi_rhs_exprs, because there's no handy function to free the memory of Node trees. Author: Ashutosh Bapat <[email protected]> Reviewed-by: Richard Guo <[email protected]> Reviewed-by: Amit Langote <[email protected]> Reviewed-by: Andrey Lepikhov <[email protected]> Reviewed-by: Tomas Vondra <[email protected]> Discussion: https://postgr.es/m/CAExHW5tHqEf3ASVqvFFcghYGPfpy7o3xnvhHwBGbJFMRH8KjNw@mail.gmail.com
-rw-r--r--src/backend/optimizer/path/joinrels.c36
-rw-r--r--src/backend/optimizer/util/pathnode.c5
-rw-r--r--src/include/nodes/pathnodes.h3
3 files changed, 42 insertions, 2 deletions
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 4750579b0a7..c59aff28226 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -45,6 +45,7 @@ static void try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1,
static SpecialJoinInfo *build_child_join_sjinfo(PlannerInfo *root,
SpecialJoinInfo *parent_sjinfo,
Relids left_relids, Relids right_relids);
+static void free_child_join_sjinfo(SpecialJoinInfo *child_sjinfo);
static void compute_partition_bounds(PlannerInfo *root, RelOptInfo *rel1,
RelOptInfo *rel2, RelOptInfo *joinrel,
SpecialJoinInfo *parent_sjinfo,
@@ -1659,6 +1660,7 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
child_restrictlist);
pfree(appinfos);
+ free_child_join_sjinfo(child_sjinfo);
}
}
@@ -1666,6 +1668,9 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
* Construct the SpecialJoinInfo for a child-join by translating
* SpecialJoinInfo for the join between parents. left_relids and right_relids
* are the relids of left and right side of the join respectively.
+ *
+ * If translations are added to or removed from this function, consider
+ * updating free_child_join_sjinfo() accordingly.
*/
static SpecialJoinInfo *
build_child_join_sjinfo(PlannerInfo *root, SpecialJoinInfo *parent_sjinfo,
@@ -1706,6 +1711,37 @@ build_child_join_sjinfo(PlannerInfo *root, SpecialJoinInfo *parent_sjinfo,
}
/*
+ * free_child_join_sjinfo
+ * Free memory consumed by a SpecialJoinInfo created by
+ * build_child_join_sjinfo()
+ *
+ * Only members that are translated copies of their counterpart in the parent
+ * SpecialJoinInfo are freed here.
+ */
+static void
+free_child_join_sjinfo(SpecialJoinInfo *sjinfo)
+{
+ /*
+ * Dummy SpecialJoinInfos of inner joins do not have any translated fields
+ * and hence no fields that to be freed.
+ */
+ if (sjinfo->jointype != JOIN_INNER)
+ {
+ bms_free(sjinfo->min_lefthand);
+ bms_free(sjinfo->min_righthand);
+ bms_free(sjinfo->syn_lefthand);
+ bms_free(sjinfo->syn_righthand);
+
+ /*
+ * semi_rhs_exprs may in principle be freed, but a simple pfree() does
+ * not suffice, so we leave it alone.
+ */
+ }
+
+ pfree(sjinfo);
+}
+
+/*
* compute_partition_bounds
* Compute the partition bounds for a join rel from those for inputs
*/
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 0a7e5c2678f..c29ca5a0da2 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1707,8 +1707,9 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
pathnode->subpath = subpath;
/*
- * Under GEQO, the sjinfo might be short-lived, so we'd better make copies
- * of data structures we extract from it.
+ * Under GEQO and when planning child joins, the sjinfo might be
+ * short-lived, so we'd better make copies of data structures we extract
+ * from it.
*/
pathnode->in_operators = copyObject(sjinfo->semi_operators);
pathnode->uniq_exprs = copyObject(sjinfo->semi_rhs_exprs);
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index b3069516b24..08dbee002fe 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -2856,6 +2856,9 @@ typedef struct PlaceHolderVar
* cost estimation purposes it is sometimes useful to know the join size under
* plain innerjoin semantics. Note that lhs_strict and the semi_xxx fields
* are not set meaningfully within such structs.
+ *
+ * We also create transient SpecialJoinInfos for child joins during
+ * partiotionwise join planning, which are also not present in join_info_list.
*/
#ifndef HAVE_SPECIALJOININFO_TYPEDEF
typedef struct SpecialJoinInfo SpecialJoinInfo;