diff options
author | Robert Haas | 2024-08-30 19:57:47 +0000 |
---|---|---|
committer | Robert Haas | 2024-08-30 19:57:47 +0000 |
commit | 2ba2a46dd47f270b0cb3c8c89eeb2a445f6f9275 (patch) | |
tree | 76bfd673c8aa79559f38daea5739e03ee939e4d1 /src/backend | |
parent | 9ad86322ddd8713695e3fa74a0287c26a424df30 (diff) |
Also subdivide merge join.joinadvice
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 49 | ||||
-rw-r--r-- | src/backend/optimizer/path/joinpath.c | 2 |
3 files changed, 39 insertions, 18 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 7ed03b33a7..8fbf110b13 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -3374,7 +3374,11 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist) if (enable_hashjoin) jsa_mask |= JSA_HASHJOIN; if (enable_mergejoin) - jsa_mask |= JSA_MERGEJOIN; + { + jsa_mask |= JSA_MERGEJOIN_PLAIN; + if (enable_material) + jsa_mask |= JSA_MERGEJOIN_MATERIALIZE; + } if (enable_nestloop) { jsa_mask |= JSA_NESTLOOP_PLAIN; diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 38ad8fb50e..0700c634bf 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -3676,7 +3676,12 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace, Assert(outerstartsel <= outerendsel); Assert(innerstartsel <= innerendsel); - disabled_nodes = (extra->jsa_mask & JSA_MERGEJOIN) == 0 ? 1 : 0; + /* + * Assume for now that this node is not itself disabled. We'll sort out + * whether that's really the case in final_cost_mergejoin(); here, we'll + * just account for any disabled child nodes. + */ + disabled_nodes = 0; /* cost of source data */ @@ -3814,9 +3819,6 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path, rescannedtuples; double rescanratio; - /* Set the number of disabled nodes. */ - path->jpath.path.disabled_nodes = workspace->disabled_nodes; - /* Protect some assumptions below that rowcounts aren't zero */ if (inner_path_rows <= 0) inner_path_rows = 1; @@ -3943,16 +3945,20 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path, path->materialize_inner = false; /* - * Prefer materializing if it looks cheaper, unless the user has asked to - * suppress materialization. + * If merge joins with materialization are enabled, then choose + * materialization if either (a) it looks cheaper or (b) merge joins + * without materialization are disabled. */ - else if (enable_material && mat_inner_cost < bare_inner_cost) + else if ((extra->jsa_mask & JSA_MERGEJOIN_MATERIALIZE) != 0 && + (mat_inner_cost < bare_inner_cost || + (extra->jsa_mask & JSA_MERGEJOIN_PLAIN) == 0)) path->materialize_inner = true; /* - * Even if materializing doesn't look cheaper, we *must* do it if the - * inner path is to be used directly (without sorting) and it doesn't - * support mark/restore. + * Regardless of what plan shapes are enabled and what the costs seem + * to be, we *must* materialize it if the inner path is to be used directly + * (without sorting) and it doesn't support mark/restore. Planner failure + * is not an option! * * Since the inner side must be ordered, and only Sorts and IndexScans can * create order to begin with, and they both support mark/restore, you @@ -3960,10 +3966,6 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path, * merge joins can *preserve* the order of their inputs, so they can be * selected as the input of a mergejoin, and they don't support * mark/restore at present. - * - * We don't test the value of enable_material here, because - * materialization is required for correctness in this case, and turning - * it off does not entitle us to deliver an invalid plan. */ else if (innersortkeys == NIL && !ExecSupportsMarkRestore(inner_path)) @@ -3980,7 +3982,8 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path, * rather than necessary for correctness, we skip it if enable_material is * off. */ - else if (enable_material && innersortkeys != NIL && + else if ((extra->jsa_mask & JSA_MERGEJOIN_MATERIALIZE) != 0 && + innersortkeys != NIL && relation_byte_size(inner_path_rows, inner_path->pathtarget->width) > (work_mem * 1024L)) @@ -3988,11 +3991,25 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path, else path->materialize_inner = false; - /* Charge the right incremental cost for the chosen case */ + /* Get the number of disabled nodes, not yet including this one. */ + path->jpath.path.disabled_nodes = workspace->disabled_nodes; + + /* + * Charge the right incremental cost for the chosen case, and increment + * disabled_nodes if appropriate. + */ if (path->materialize_inner) + { run_cost += mat_inner_cost; + if ((extra->jsa_mask & JSA_MERGEJOIN_MATERIALIZE) == 0) + ++path->jpath.path.disabled_nodes; + } else + { run_cost += bare_inner_cost; + if ((extra->jsa_mask & JSA_MERGEJOIN_PLAIN) == 0) + ++path->jpath.path.disabled_nodes; + } /* CPU costs */ diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index d853e2a64e..0ef7e776fe 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -237,7 +237,7 @@ add_paths_to_joinrel(PlannerInfo *root, * way of implementing a full outer join, so in that case we don't care * whether mergejoins are disabled. */ - if ((extra.jsa_mask & JSA_MERGEJOIN) != 0 || jointype == JOIN_FULL) + if ((extra.jsa_mask & JSA_MERGEJOIN_ANY) != 0 || jointype == JOIN_FULL) extra.mergeclause_list = select_mergejoin_clauses(root, joinrel, outerrel, |