From 5777b1bd17e06fdbc5e8cf55bee6ae38ad623d76 Mon Sep 17 00:00:00 2001
From: Chengpeng Yan <chengpeng_yan@outlook.com>
Date: Tue, 16 Dec 2025 20:15:44 +0800
Subject: [PATCH v3 2/2] add a GUC goo_greedy_strategy to choose different GOO 
 greedy strategic to test

Signed-off-by: Chengpeng Yan <chengpeng_yan@outlook.com>
---
 src/backend/optimizer/path/goo.c          | 36 ++++++++++++++++++++++-
 src/backend/utils/misc/guc_parameters.dat | 10 +++++++
 src/backend/utils/misc/guc_tables.c       |  8 +++++
 src/include/optimizer/paths.h             |  8 +++++
 4 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/backend/optimizer/path/goo.c b/src/backend/optimizer/path/goo.c
index 247dbb5f921..64ea7667315 100644
--- a/src/backend/optimizer/path/goo.c
+++ b/src/backend/optimizer/path/goo.c
@@ -55,6 +55,7 @@
  * Configuration defaults.  These are exposed as GUCs in guc_tables.c.
  */
 bool		enable_goo_join_search = false;
+int			goo_greedy_strategy = GOO_GREEDY_STRATEGY_COST;
 
 /*
  * Working state for a single GOO search invocation.
@@ -94,6 +95,9 @@ typedef struct GooCandidate
 {
 	RelOptInfo *left;			/* left input clump */
 	RelOptInfo *right;			/* right input clump */
+	double		rows;			/* estimated join cardinality */
+	double		selectivity;	/* join selectivity */
+	double		result_size;	/* estimated result size in bytes */
 	Cost		total_cost;		/* total cost of cheapest path */
 }			GooCandidate;
 
@@ -417,6 +421,11 @@ static GooCandidate * goo_build_candidate(GooState * state, RelOptInfo *left,
 	int			saved_rel_len;
 	struct HTAB *saved_hash;
 	RelOptInfo *joinrel;
+	double		join_rows;
+	double		left_rows;
+	double		right_rows;
+	double		selectivity = 0.0;
+	double		result_size;
 	Cost		total_cost;
 	GooCandidate *cand;
 
@@ -477,6 +486,14 @@ static GooCandidate * goo_build_candidate(GooState * state, RelOptInfo *left,
 		set_cheapest(grouped_rel);
 	}
 
+	join_rows = joinrel->rows;
+	left_rows = left->rows;
+	right_rows = right->rows;
+
+	if (left_rows > 0 && right_rows > 0)
+		selectivity = join_rows / (left_rows * right_rows);
+
+	result_size = join_rows * joinrel->reltarget->width;
 	total_cost = joinrel->cheapest_total_path->total_cost;
 
 	/*
@@ -495,6 +512,9 @@ static GooCandidate * goo_build_candidate(GooState * state, RelOptInfo *left,
 	cand = palloc(sizeof(GooCandidate));
 	cand->left = left;
 	cand->right = right;
+	cand->rows = join_rows;
+	cand->selectivity = selectivity;
+	cand->result_size = result_size;
 	cand->total_cost = total_cost;
 	MemoryContextSwitchTo(oldcxt);
 
@@ -608,5 +628,19 @@ goo_commit_join(GooState * state, GooCandidate * cand)
 static bool
 goo_candidate_better(GooCandidate * a, GooCandidate * b)
 {
-	return (a->total_cost < b->total_cost);
+	switch (goo_greedy_strategy)
+	{
+		case GOO_GREEDY_STRATEGY_ROWS:
+			return a->rows < b->rows;
+
+		case GOO_GREEDY_STRATEGY_SELECTIVITY:
+			return a->selectivity < b->selectivity;
+
+		case GOO_GREEDY_STRATEGY_RESULT_SIZE:
+			return a->result_size < b->result_size;
+
+		case GOO_GREEDY_STRATEGY_COST:
+		default:
+			return a->total_cost < b->total_cost;
+	}
 }
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index a8ce31ab8a7..26d72283e7d 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -1154,6 +1154,16 @@
   max => 'MAX_KILOBYTES',
 },
 
+/* WIP: only for testing */
+{ name => 'goo_greedy_strategy', type => 'enum', context => 'PGC_USERSET', group => 'QUERY_TUNING_GEQO',
+  short_desc => 'Selects the heuristic used by GOO to compare join candidates.',
+  long_desc => 'Valid values are cost, rows, selectivity, and result_size.',
+  flags => 'GUC_EXPLAIN',
+  variable => 'goo_greedy_strategy',
+  boot_val => 'GOO_GREEDY_STRATEGY_COST',
+  options => 'goo_greedy_strategy_options',
+},
+
 { name => 'gss_accept_delegation', type => 'bool', context => 'PGC_SIGHUP', group => 'CONN_AUTH_AUTH',
   short_desc => 'Sets whether GSSAPI delegation should be accepted from the client.',
   variable => 'pg_gss_accept_delegation',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index f87b558c2c6..f8812d65294 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -411,6 +411,14 @@ static const struct config_enum_entry plan_cache_mode_options[] = {
 	{NULL, 0, false}
 };
 
+static const struct config_enum_entry goo_greedy_strategy_options[] = {
+	{"cost", GOO_GREEDY_STRATEGY_COST, false},
+	{"rows", GOO_GREEDY_STRATEGY_ROWS, false},
+	{"selectivity", GOO_GREEDY_STRATEGY_SELECTIVITY, false},
+	{"result_size", GOO_GREEDY_STRATEGY_RESULT_SIZE, false},
+	{NULL, 0, false}
+};
+
 static const struct config_enum_entry password_encryption_options[] = {
 	{"md5", PASSWORD_TYPE_MD5, false},
 	{"scram-sha-256", PASSWORD_TYPE_SCRAM_SHA_256, false},
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 5b3ebe5f1d2..28846d01d3a 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -16,12 +16,20 @@
 
 #include "nodes/pathnodes.h"
 
+typedef enum GooGreedyStrategy
+{
+	GOO_GREEDY_STRATEGY_COST,
+	GOO_GREEDY_STRATEGY_ROWS,
+	GOO_GREEDY_STRATEGY_SELECTIVITY,
+	GOO_GREEDY_STRATEGY_RESULT_SIZE
+}			GooGreedyStrategy;
 
 /*
  * allpaths.c
  */
 extern PGDLLIMPORT bool enable_geqo;
 extern PGDLLIMPORT bool enable_goo_join_search;
+extern PGDLLIMPORT int goo_greedy_strategy;
 extern PGDLLIMPORT bool enable_eager_aggregate;
 extern PGDLLIMPORT int geqo_threshold;
 extern PGDLLIMPORT double min_eager_agg_group_size;
-- 
2.39.3 (Apple Git-146)

