summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/optimizer/path/allpaths.c6
-rw-r--r--src/backend/optimizer/path/costsize.c49
-rw-r--r--src/backend/optimizer/path/joinpath.c2
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,