From d4e87b591b39cd6325f4e787f0d3408421823a93 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Wed, 28 May 2025 16:06:48 -0400 Subject: [PATCH] hackity hack --- contrib/pg_plan_advice/pg_plan_advice.c | 13 ++- contrib/pg_plan_advice/pgpa_join.c | 111 +++++++++++++++++++----- contrib/pg_plan_advice/pgpa_join.h | 4 +- contrib/pg_plan_advice/pgpa_walker.c | 31 ++++++- contrib/pg_plan_advice/pgpa_walker.h | 1 + 5 files changed, 130 insertions(+), 30 deletions(-) diff --git a/contrib/pg_plan_advice/pg_plan_advice.c b/contrib/pg_plan_advice/pg_plan_advice.c index 687211b17d..9a5a9daa9b 100644 --- a/contrib/pg_plan_advice/pg_plan_advice.c +++ b/contrib/pg_plan_advice/pg_plan_advice.c @@ -59,11 +59,18 @@ pgpa_check_plan(PlannedStmt *pstmt) initStringInfo(&buf); foreach(lc, context.unrolled_joins) { - pgpa_unrolled_join *join = lfirst(lc); + pgpa_unrolled_join *ujoin = lfirst(lc); appendStringInfoChar(&buf, ' '); - pgpa_debug_out_unrolled_join(&buf, join); + pgpa_debug_out_unrolled_join(&buf, ujoin); + } + foreach(lc, context.clumped_joins) + { + pgpa_clumped_join *cjoin = lfirst(lc); + + appendStringInfoChar(&buf, ' '); + pgpa_debug_out_clumped_join(&buf, cjoin); } - elog(WARNING, "unrolled joins:%s", buf.data); + elog(WARNING, "advice:%s", buf.data); } diff --git a/contrib/pg_plan_advice/pgpa_join.c b/contrib/pg_plan_advice/pgpa_join.c index 8bb6a2987d..e51d6ed632 100644 --- a/contrib/pg_plan_advice/pgpa_join.c +++ b/contrib/pg_plan_advice/pgpa_join.c @@ -19,6 +19,7 @@ static pgpa_join_strategy pgpa_decompose_join(Plan *plan, Plan **realinner, Plan **realouter); static Index pgpa_scanrelid(Plan *plan); +static Bitmapset *pgpa_relids(Plan *plan); static void pgpa_debug_out_join_member(StringInfo buf, pgpa_join_member *member); @@ -32,8 +33,6 @@ static char *pgpa_cstring_join_strategy(pgpa_join_strategy strategy); pgpa_join_class pgpa_get_join_class(Plan *plan) { - Bitmapset *relids = NULL; - /* Standard join types can be unrolled. */ if (IsA(plan, NestLoop) || IsA(plan, MergeJoin) || IsA(plan, HashJoin)) return PGPA_UNROLLED_JOIN; @@ -43,19 +42,38 @@ pgpa_get_join_class(Plan *plan) * has multiple relids, then it's a clumped join; otherwise, it's not a * join at all. */ + if (bms_membership(pgpa_relids(plan)) == BMS_MULTIPLE) + return PGPA_CLUMPED_JOIN; + + /* Doesn't seem to be a join. */ + return PGPA_NON_JOIN; +} + +/* + * Build a pgpa_clumped_join object for a Plan node. + */ +pgpa_clumped_join * +pgpa_build_clumped_join(Plan *plan) +{ + pgpa_clumped_join *clump = palloc(sizeof(pgpa_clumped_join)); + + Assert(pgpa_get_join_class(plan) == PGPA_CLUMPED_JOIN); + + clump->plan = plan; + clump->relids = pgpa_relids(plan); + if (IsA(plan, Result)) - relids = ((Result *) plan)->relids; + clump->strategy = JSTRAT_CLUMP_DEGENERATE; else if (IsA(plan, ForeignScan)) - relids = ((ForeignScan *) plan)->fs_relids; + clump->strategy = JSTRAT_CLUMP_FOREIGN; else if (IsA(plan, Append)) - relids = ((Append *) plan)->apprelids; + clump->strategy = JSTRAT_CLUMP_PARTITIONWISE; else if (IsA(plan, MergeAppend)) - relids = ((MergeAppend *) plan)->apprelids; - if (bms_membership(relids) == BMS_MULTIPLE) - return PGPA_CLUMPED_JOIN; + clump->strategy = JSTRAT_CLUMP_PARTITIONWISE; + else + elog(ERROR, "unexpected plan type"); - /* Doesn't seem to be a join. */ - return PGPA_NON_JOIN; + return clump; } /* @@ -105,7 +123,7 @@ pgpa_unroll_join(PlannedStmt *pstmt, Plan *plan, * * XXX. Gather and Gather Merge are going to be a problem here. */ - if (IsA(plan, Material) || IsA(plan, Memoize) || IsA(plan, Hash)) + if (IsA(plan, Material) || IsA(plan, Memoize) || IsA(plan, Hash) || IsA(plan, Sort)) { *outer_join_unroller = join_unroller; return; @@ -181,12 +199,16 @@ pgpa_build_unrolled_join(PlannedStmt *pstmt, /* Allocate result structures. */ ujoin = palloc0_object(pgpa_unrolled_join); - ujoin->outer.plan = join_unroller->outer_subplan; - ujoin->outer.rti = pgpa_scanrelid(ujoin->outer.plan); ujoin->ninner = join_unroller->nused; ujoin->strategy = palloc0_array(pgpa_join_strategy, join_unroller->nused); ujoin->inner = palloc0_array(pgpa_join_member, join_unroller->nused); + /* Handle the outermost join. */ + ujoin->outer.plan = join_unroller->outer_subplan; + ujoin->outer.rti = pgpa_scanrelid(ujoin->outer.plan); + if (pgpa_get_join_class(ujoin->outer.plan) == PGPA_CLUMPED_JOIN) + ujoin->outer.clump_join = pgpa_build_clumped_join(ujoin->outer.plan); + /* * We want the joins from the deepest part of the plan tree to appear * first in the result object, but the join unroller adds them in exactly @@ -213,8 +235,13 @@ pgpa_build_unrolled_join(PlannedStmt *pstmt, ujoin->inner[i].rti = pgpa_scanrelid(ujoin->inner[i].plan); /* - * XXX. What about clumped join and elided node? - */ + * If we need a clumped join object, build one. + */ + if (pgpa_get_join_class(ujoin->inner[i].plan) == PGPA_CLUMPED_JOIN) + ujoin->inner[i].clump_join = + pgpa_build_clumped_join(ujoin->inner[i].plan); + + /* XXX. What about elided nodes? */ } return ujoin; @@ -240,11 +267,14 @@ pgpa_destroy_join_unroller(pgpa_join_unroller *join_unroller) * for all intents and purposes the real inner input is the Hash node's child, * not the Hash node itself. * - * Neither a Merge Join or a Nested Loop has any mandatory subnodes the way - * a Hash Join does, but the join planning code does consider add additional - * nodes such as Materialize. When such nodes are present, we regard them as - * an aspect of the join strategy, not an input to the join. The true inner - * or outer node is whatever lies beneath any such node. + * Likewise, a Merge Join may have Sort note on the inner or outer side; if + * it does, the real input to the join is the Sort node's child, not the + * Sort node itself. + * + * In addition, with a Merge Join or a Nested Loop, the join planning code + * may add additional nodes such as Materialize or Memoize. We regard these + * as an aspect of the join strategy. As in the previous cases, the true input + * to the join is the underlying node. */ static pgpa_join_strategy pgpa_decompose_join(Plan *plan, Plan **realinner, Plan **realouter) @@ -256,6 +286,10 @@ pgpa_decompose_join(Plan *plan, Plan **realinner, Plan **realouter) switch (nodeTag(plan)) { case T_MergeJoin: + if (IsA(innerplan, Sort)) + innerplan = innerplan->lefttree; + if (IsA(outerplan, Sort)) + outerplan = outerplan->lefttree; if (IsA(innerplan, Material)) { innerplan = innerplan->lefttree; @@ -292,6 +326,11 @@ pgpa_decompose_join(Plan *plan, Plan **realinner, Plan **realouter) return strategy; } +/* + * Extract the scanned RTI from a plan node. + * + * Returns 0 if there isn't one. + */ static Index pgpa_scanrelid(Plan *plan) { @@ -314,10 +353,40 @@ pgpa_scanrelid(Plan *plan) case T_IndexOnlyScan: return ((Scan *) plan)->scanrelid; default: - return 0; + { + Bitmapset *relids = pgpa_relids(plan); + + /* + * If the node type is capable of carrying multiple relids + * but the relids set actually present has exactly one member, + * we regard it as a scan. + */ + if (bms_membership(relids) == BMS_SINGLETON) + return bms_singleton_member(relids); + + return 0; + } } } +/* + * Certain plan nodes can refer to a set of RTIs. Extract and return the set. + */ +static Bitmapset * +pgpa_relids(Plan *plan) +{ + if (IsA(plan, Result)) + return ((Result *) plan)->relids; + else if (IsA(plan, ForeignScan)) + return ((ForeignScan *) plan)->fs_relids; + else if (IsA(plan, Append)) + return ((Append *) plan)->apprelids; + else if (IsA(plan, MergeAppend)) + return ((MergeAppend *) plan)->apprelids; + + return NULL; +} + void pgpa_debug_out_clumped_join(StringInfo buf, pgpa_clumped_join *clump) { diff --git a/contrib/pg_plan_advice/pgpa_join.h b/contrib/pg_plan_advice/pgpa_join.h index a8f82deb3a..f6161b7f4a 100644 --- a/contrib/pg_plan_advice/pgpa_join.h +++ b/contrib/pg_plan_advice/pgpa_join.h @@ -48,8 +48,8 @@ typedef enum typedef struct { Plan *plan; - Bitmapset *relids; pgpa_join_clump_strategy strategy; + Bitmapset *relids; } pgpa_clumped_join; /* @@ -132,7 +132,7 @@ typedef enum } pgpa_join_class; extern pgpa_join_class pgpa_get_join_class(Plan *plan); -extern pgpa_clumped_join *pgpa_make_clumped_join(Plan *plan); +extern pgpa_clumped_join *pgpa_build_clumped_join(Plan *plan); extern pgpa_join_unroller *pgpa_create_join_unroller(void); extern void pgpa_unroll_join(PlannedStmt *pstmt, Plan *plan, diff --git a/contrib/pg_plan_advice/pgpa_walker.c b/contrib/pg_plan_advice/pgpa_walker.c index 349af23dfb..597ab90a4b 100644 --- a/contrib/pg_plan_advice/pgpa_walker.c +++ b/contrib/pg_plan_advice/pgpa_walker.c @@ -12,14 +12,37 @@ pgpa_plan_walker(pgpa_plan_walker_context *context, Plan *plan, pgpa_join_unroller *outer_join_unroller = NULL; pgpa_join_unroller *inner_join_unroller = NULL; bool join_unroller_toplevel = false; + pgpa_join_class class; ListCell *lc; List *extraplans = NIL; - if (join_unroller == NULL && - pgpa_get_join_class(plan) == PGPA_UNROLLED_JOIN) + foreach_node(ElidedNode, n, context->pstmt->elidedNodes) { - join_unroller = pgpa_create_join_unroller(); - join_unroller_toplevel = true; + if (n->plan_node_id != plan->plan_node_id) + continue; + + n->elided_type; + n->relids; + + elog(WARNING, "look at me, i'm elided!"); + } + + class = pgpa_get_join_class(plan); + + if (join_unroller == NULL) + { + if (class == PGPA_UNROLLED_JOIN) + { + join_unroller = pgpa_create_join_unroller(); + join_unroller_toplevel = true; + } + else if (class == PGPA_CLUMPED_JOIN) + { + pgpa_clumped_join *cjoin; + + cjoin = pgpa_build_clumped_join(plan); + context->clumped_joins = lappend(context->clumped_joins, cjoin); + } } if (join_unroller != NULL) pgpa_unroll_join(context->pstmt, plan, join_unroller, diff --git a/contrib/pg_plan_advice/pgpa_walker.h b/contrib/pg_plan_advice/pgpa_walker.h index b50bb687f2..353c9ebc8a 100644 --- a/contrib/pg_plan_advice/pgpa_walker.h +++ b/contrib/pg_plan_advice/pgpa_walker.h @@ -4,6 +4,7 @@ typedef struct pgpa_plan_walker_context { PlannedStmt *pstmt; List *unrolled_joins; + List *clumped_joins; } pgpa_plan_walker_context; extern void -- 2.39.5