diff options
author | Amit Langote | 2024-03-25 03:02:40 +0000 |
---|---|---|
committer | Amit Langote | 2024-03-25 09:06:46 +0000 |
commit | 5278d0a2e870c61f9374a7796b90e6f9f6a73638 (patch) | |
tree | 065299c04b8ad160394bf832a33dcfe53d226617 | |
parent | 619bc23a1a2f3750ac3668fe5a7564bc51e01684 (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.c | 36 | ||||
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 5 | ||||
-rw-r--r-- | src/include/nodes/pathnodes.h | 3 |
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; |