summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas2024-08-30 19:11:23 +0000
committerRobert Haas2024-08-30 19:11:23 +0000
commit9ad86322ddd8713695e3fa74a0287c26a424df30 (patch)
tree75678b324b0dd706a36079e34bc9c4a2c8237253
parent868dc508088e734021099e5716f9e6da4de8337f (diff)
Split up nested loops.
-rw-r--r--src/backend/optimizer/path/allpaths.c12
-rw-r--r--src/backend/optimizer/path/costsize.c8
-rw-r--r--src/backend/optimizer/path/joinpath.c42
-rw-r--r--src/backend/optimizer/plan/createplan.c1
-rw-r--r--src/backend/optimizer/util/pathnode.c6
-rw-r--r--src/include/optimizer/cost.h4
-rw-r--r--src/include/optimizer/pathnode.h3
-rw-r--r--src/include/optimizer/paths.h29
8 files changed, 46 insertions, 59 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 8f18a6f00a..7ed03b33a7 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -894,7 +894,7 @@ set_tablesample_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *
bms_membership(root->all_query_rels) != BMS_SINGLETON) &&
!(GetTsmRoutine(rte->tablesample->tsmhandler)->repeatable_across_scans))
{
- path = (Path *) create_material_path(rel, path);
+ path = (Path *) create_material_path(rel, path, enable_material);
}
add_path(rel, path);
@@ -3373,12 +3373,16 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
jsa_mask = JSA_FOREIGN;
if (enable_hashjoin)
jsa_mask |= JSA_HASHJOIN;
- if (enable_material)
- jsa_mask |= JSA_NESTLOOP_MATERIALIZE;
if (enable_mergejoin)
jsa_mask |= JSA_MERGEJOIN;
if (enable_nestloop)
- jsa_mask |= JSA_NESTLOOP;
+ {
+ jsa_mask |= JSA_NESTLOOP_PLAIN;
+ if (enable_material)
+ jsa_mask |= JSA_NESTLOOP_MATERIALIZE;
+ if (enable_memoize)
+ jsa_mask |= JSA_NESTLOOP_MEMOIZE;
+ }
if (enable_partitionwise_join)
jsa_mask |= JSA_PARTITIONWISE;
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 19717a5324..38ad8fb50e 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -2481,7 +2481,7 @@ cost_merge_append(Path *path, PlannerInfo *root,
*/
void
cost_material(Path *path,
- int input_disabled_nodes,
+ bool enabled, int input_disabled_nodes,
Cost input_startup_cost, Cost input_total_cost,
double tuples, int width)
{
@@ -2519,7 +2519,7 @@ cost_material(Path *path,
run_cost += seq_page_cost * npages;
}
- path->disabled_nodes = input_disabled_nodes + (enable_material ? 0 : 1);
+ path->disabled_nodes = input_disabled_nodes + (enabled ? 0 : 1);
path->startup_cost = startup_cost;
path->total_cost = startup_cost + run_cost;
}
@@ -3266,7 +3266,7 @@ cost_group(Path *path, PlannerInfo *root,
*/
void
initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace,
- JoinType jointype,
+ JoinType jointype, unsigned nestloop_subtype,
Path *outer_path, Path *inner_path,
JoinPathExtraData *extra)
{
@@ -3280,7 +3280,7 @@ initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace,
Cost inner_rescan_run_cost;
/* Count up disabled nodes. */
- disabled_nodes = (extra->jsa_mask & JSA_NESTLOOP) == 0 ? 1 : 0;
+ disabled_nodes = (extra->jsa_mask & nestloop_subtype) == 0 ? 1 : 0;
disabled_nodes += inner_path->disabled_nodes;
disabled_nodes += outer_path->disabled_nodes;
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 4fa6c3d918..d853e2a64e 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -862,6 +862,7 @@ try_nestloop_path(PlannerInfo *root,
Path *inner_path,
List *pathkeys,
JoinType jointype,
+ unsigned nestloop_subtype,
JoinPathExtraData *extra)
{
Relids required_outer;
@@ -946,7 +947,7 @@ try_nestloop_path(PlannerInfo *root,
* The latter two steps are expensive enough to make this two-phase
* methodology worthwhile.
*/
- initial_cost_nestloop(root, &workspace, jointype,
+ initial_cost_nestloop(root, &workspace, jointype, nestloop_subtype,
outer_path, inner_path, extra);
if (add_path_precheck(joinrel, workspace.disabled_nodes,
@@ -984,6 +985,7 @@ try_partial_nestloop_path(PlannerInfo *root,
Path *inner_path,
List *pathkeys,
JoinType jointype,
+ unsigned nestloop_subtype,
JoinPathExtraData *extra)
{
JoinCostWorkspace workspace;
@@ -1031,7 +1033,7 @@ try_partial_nestloop_path(PlannerInfo *root,
* Before creating a path, get a quick lower bound on what it is likely to
* cost. Bail out right away if it looks terrible.
*/
- initial_cost_nestloop(root, &workspace, jointype,
+ initial_cost_nestloop(root, &workspace, jointype, nestloop_subtype,
outer_path, inner_path, extra);
if (!add_partial_path_precheck(joinrel, workspace.disabled_nodes,
workspace.total_cost, pathkeys))
@@ -1939,17 +1941,8 @@ match_unsorted_outer(PlannerInfo *root,
if ((extra->jsa_mask & JSA_NESTLOOP_MATERIALIZE) != 0 &&
inner_cheapest_total != NULL &&
!ExecMaterializesOutput(inner_cheapest_total->pathtype))
- {
matpath = (Path *)
- create_material_path(innerrel, inner_cheapest_total);
-
- /*
- * Ignore create_material_path()'s idea of whether the path is
- * disabled in general; JSA_NESTLOOP_MATERIALIZE means it is
- * acceptable here.
- */
- matpath->disabled_nodes = inner_cheapest_total->disabled_nodes;
- }
+ create_material_path(innerrel, inner_cheapest_total, true);
}
foreach(lc1, outerrel->pathlist)
@@ -1997,6 +1990,7 @@ match_unsorted_outer(PlannerInfo *root,
inner_cheapest_total,
merge_pathkeys,
jointype,
+ JSA_NESTLOOP_PLAIN,
extra);
}
else if (nestjoinOK)
@@ -2020,6 +2014,7 @@ match_unsorted_outer(PlannerInfo *root,
innerpath,
merge_pathkeys,
jointype,
+ JSA_NESTLOOP_PLAIN,
extra);
/*
@@ -2036,6 +2031,7 @@ match_unsorted_outer(PlannerInfo *root,
mpath,
merge_pathkeys,
jointype,
+ JSA_NESTLOOP_MEMOIZE,
extra);
}
@@ -2047,6 +2043,7 @@ match_unsorted_outer(PlannerInfo *root,
matpath,
merge_pathkeys,
jointype,
+ JSA_NESTLOOP_MATERIALIZE,
extra);
}
@@ -2188,18 +2185,8 @@ consider_parallel_nestloop(PlannerInfo *root,
inner_cheapest_total->parallel_safe &&
!PATH_PARAM_BY_REL(inner_cheapest_total, outerrel) &&
!ExecMaterializesOutput(inner_cheapest_total->pathtype))
- {
matpath = (Path *)
- create_material_path(innerrel, inner_cheapest_total);
- Assert(matpath->parallel_safe);
-
- /*
- * Ignore create_material_path()'s idea of whether the path is
- * disabled in general; JSA_NESTLOOP_MATERIALIZE means it is
- * acceptable here.
- */
- matpath->disabled_nodes = inner_cheapest_total->disabled_nodes;
- }
+ create_material_path(innerrel, inner_cheapest_total, true);
foreach(lc1, outerrel->partial_pathlist)
{
@@ -2244,7 +2231,8 @@ consider_parallel_nestloop(PlannerInfo *root,
}
try_partial_nestloop_path(root, joinrel, outerpath, innerpath,
- pathkeys, jointype, extra);
+ pathkeys, jointype, JSA_NESTLOOP_PLAIN,
+ extra);
/*
* Try generating a memoize path and see if that makes the nested
@@ -2255,13 +2243,15 @@ consider_parallel_nestloop(PlannerInfo *root,
extra);
if (mpath != NULL)
try_partial_nestloop_path(root, joinrel, outerpath, mpath,
- pathkeys, jointype, extra);
+ pathkeys, jointype,
+ JSA_NESTLOOP_MEMOIZE, extra);
}
/* Also consider materialized form of the cheapest inner path */
if (matpath != NULL)
try_partial_nestloop_path(root, joinrel, outerpath, matpath,
- pathkeys, jointype, extra);
+ pathkeys, jointype,
+ JSA_NESTLOOP_MATERIALIZE, extra);
}
}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 8e0e5977a9..7372232b81 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -6550,6 +6550,7 @@ materialize_finished_plan(Plan *subplan)
/* Set cost data */
cost_material(&matpath,
+ enable_material,
subplan->disabled_nodes,
subplan->startup_cost,
subplan->total_cost,
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index fc97bf6ee2..a704d0cd7b 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1631,7 +1631,7 @@ create_group_result_path(PlannerInfo *root, RelOptInfo *rel,
* pathnode.
*/
MaterialPath *
-create_material_path(RelOptInfo *rel, Path *subpath)
+create_material_path(RelOptInfo *rel, Path *subpath, bool enabled)
{
MaterialPath *pathnode = makeNode(MaterialPath);
@@ -1650,6 +1650,7 @@ create_material_path(RelOptInfo *rel, Path *subpath)
pathnode->subpath = subpath;
cost_material(&pathnode->path,
+ enabled,
subpath->disabled_nodes,
subpath->startup_cost,
subpath->total_cost,
@@ -4158,7 +4159,8 @@ reparameterize_path(PlannerInfo *root, Path *path,
loop_count);
if (spath == NULL)
return NULL;
- return (Path *) create_material_path(rel, spath);
+ return (Path *) create_material_path(rel, spath,
+ enable_material);
}
case T_Memoize:
{
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index 854a782944..071a8749cf 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -125,7 +125,7 @@ extern void cost_merge_append(Path *path, PlannerInfo *root,
Cost input_startup_cost, Cost input_total_cost,
double tuples);
extern void cost_material(Path *path,
- int input_disabled_nodes,
+ bool enabled, int input_disabled_nodes,
Cost input_startup_cost, Cost input_total_cost,
double tuples, int width);
extern void cost_agg(Path *path, PlannerInfo *root,
@@ -148,7 +148,7 @@ extern void cost_group(Path *path, PlannerInfo *root,
double input_tuples);
extern void initial_cost_nestloop(PlannerInfo *root,
JoinCostWorkspace *workspace,
- JoinType jointype,
+ JoinType jointype, unsigned nestloop_subtype,
Path *outer_path, Path *inner_path,
JoinPathExtraData *extra);
extern void final_cost_nestloop(PlannerInfo *root, NestPath *path,
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 266c551cac..ed2e3a1c8b 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -82,7 +82,8 @@ extern GroupResultPath *create_group_result_path(PlannerInfo *root,
RelOptInfo *rel,
PathTarget *target,
List *havingqual);
-extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
+extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath,
+ bool enabled);
extern MemoizePath *create_memoize_path(PlannerInfo *root,
RelOptInfo *rel,
Path *subpath,
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 4177d7a45a..94779eff9a 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -25,30 +25,19 @@
* mask is computed on the basis of the various enable_* GUCs, and can be
* overriden by hooks.
*
- * JSA_FOREIGN means that it's OK for a FDW to produce join paths.
- *
- * JSA_MERGEJOIN means that a mergejoin is OK.
- *
- * JSA_NESTLOOP means that a nested loop is OK in general.
- *
- * JSA_NESTLOOP_MATERIALIZE and JSA_NESTLOOP_NO_MATERIALIZE mean that it's
- * OK for a nested loop to materialize or not materialize the inner side.
- * JSA_NESTLOOP_MEMOIZE and JSA_NESTLOOP_NO_MEMOIZE mean that it's OK for
- * a nested loop to memoize or not memoize the inner side.
- *
- * JSA_HASHJOIN means that a hash join is OK.
- *
- * JSA_PARTITIONWISE means that a partitionwise join is OK.
+ * We have five main join strategie: a foreign join (when supported by the
+ * relevant FDW), a merge join, a nested loop, a hash join, and a partitionwise
+ * join. Nested loops are further subdivided depending on whether the inner
+ * side of the join is materialized, memoized, or neither (which we here call
+ * a "plain" nested loop).
*/
#define JSA_FOREIGN 0x0001
#define JSA_MERGEJOIN 0x0002
-#define JSA_NESTLOOP 0x0004
+#define JSA_NESTLOOP_PLAIN 0x0004
#define JSA_NESTLOOP_MATERIALIZE 0x0008
-#define JSA_NESTLOOP_NO_MATERIALIZE 0x0010
-#define JSA_NESTLOOP_MEMOIZE 0x0020
-#define JSA_NESTLOOP_NO_MEMOIZE 0x0040
-#define JSA_HASHJOIN 0x0080
-#define JSA_PARTITIONWISE 0x0100
+#define JSA_NESTLOOP_MEMOIZE 0x0010
+#define JSA_HASHJOIN 0x0020
+#define JSA_PARTITIONWISE 0x0040
/*
* allpaths.c