Tomas Vondra <[email protected]> writes:
> I was wondering about which places allocate most memory during planning.
> I selected a query that allocates a manageable amount (~2.5GB) to plan,
> and added some instrumentation to trace alloc/free calls for the
> PortalContext (which is the context used by the planner).

Thanks for doing this work, very interesting.

> After classifying the allocations a bit, I see this:

>            allocation                 | size
> --------------------------------------+----------------
>  find_mergeclauses_for_outer_pathkeys | 671 MB
>  generate_join_implied_equalities     | 660 MB
>  add_paths_to_joinrel                 | 242 MB
>  make_inner_pathkeys_for_merge        | 195 MB
>  estimate_num_groups                  | 92 MB
...

I experimented with the attached trivial patch, which just avoids
leaking sublists within find_mergeclauses_for_outer_pathkeys and
generate_join_implied_equalities.  I did not bother with adding
any measurement infrastructure, just watched the process's virtual
size with top(1).  What I see is that HEAD consumes about 2.6GB
and this patch gets it down to 1.8GB.  So we could move the needle
noticeably just by not wasting memory we don't have to.

                        regards, tom lane

diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index e3697df51a2..1ee6398087e 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -1602,7 +1602,7 @@ generate_join_implied_equalities(PlannerInfo *root,
 	while ((i = bms_next_member(matching_ecs, i)) >= 0)
 	{
 		EquivalenceClass *ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
-		List	   *sublist = NIL;
+		List	   *sublist;
 
 		/* ECs containing consts do not need any further enforcement */
 		if (ec->ec_has_const)
@@ -1632,6 +1632,7 @@ generate_join_implied_equalities(PlannerInfo *root,
 															  inner_rel);
 
 		result = list_concat(result, sublist);
+		list_free(sublist);
 	}
 
 	return result;
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 5eb71635d15..978ac1240d7 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -1560,7 +1560,7 @@ find_mergeclauses_for_outer_pathkeys(PlannerInfo *root,
 	{
 		PathKey    *pathkey = (PathKey *) lfirst(i);
 		EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
-		List	   *matched_restrictinfos = NIL;
+		bool		found_clauses = false;
 		ListCell   *j;
 
 		/*----------
@@ -1608,7 +1608,10 @@ find_mergeclauses_for_outer_pathkeys(PlannerInfo *root,
 			clause_ec = rinfo->outer_is_left ?
 				rinfo->left_ec : rinfo->right_ec;
 			if (clause_ec == pathkey_ec)
-				matched_restrictinfos = lappend(matched_restrictinfos, rinfo);
+			{
+				mergeclauses = lappend(mergeclauses, rinfo);
+				found_clauses = true;
+			}
 		}
 
 		/*
@@ -1616,14 +1619,8 @@ find_mergeclauses_for_outer_pathkeys(PlannerInfo *root,
 		 * sort-key positions in the pathkeys are useless.  (But we can still
 		 * mergejoin if we found at least one mergeclause.)
 		 */
-		if (matched_restrictinfos == NIL)
+		if (!found_clauses)
 			break;
-
-		/*
-		 * If we did find usable mergeclause(s) for this sort-key position,
-		 * add them to result list.
-		 */
-		mergeclauses = list_concat(mergeclauses, matched_restrictinfos);
 	}
 
 	return mergeclauses;

Reply via email to