aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/pathkeys.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/pathkeys.c')
-rw-r--r--src/backend/optimizer/path/pathkeys.c40
1 files changed, 33 insertions, 7 deletions
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index b5d6c977eef..2a1c923b4a8 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -1890,11 +1890,13 @@ find_mergeclauses_for_outer_pathkeys(PlannerInfo *root,
* Since we assume here that a sort is required, there is no particular use
* in matching any available ordering of the outerrel. (joinpath.c has an
* entirely separate code path for considering sort-free mergejoins.) Rather,
- * it's interesting to try to match the requested query_pathkeys so that a
- * second output sort may be avoided; and failing that, we try to list "more
- * popular" keys (those with the most unmatched EquivalenceClass peers)
- * earlier, in hopes of making the resulting ordering useful for as many
- * higher-level mergejoins as possible.
+ * it's interesting to try to match, or match a prefix of the requested
+ * query_pathkeys so that a second output sort may be avoided or an
+ * incremental sort may be done instead. We can get away with just a prefix
+ * of the query_pathkeys when that prefix covers the entire join condition.
+ * Failing that, we try to list "more popular" keys (those with the most
+ * unmatched EquivalenceClass peers) earlier, in hopes of making the resulting
+ * ordering useful for as many higher-level mergejoins as possible.
*/
List *
select_outer_pathkeys_for_merge(PlannerInfo *root,
@@ -1964,11 +1966,16 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
/*
* Find out if we have all the ECs mentioned in query_pathkeys; if so we
- * can generate a sort order that's also useful for final output. There is
- * no percentage in a partial match, though, so we have to have 'em all.
+ * can generate a sort order that's also useful for final output. If we
+ * only have a prefix of the query_pathkeys, and that prefix is the entire
+ * join condition, then it's useful to use the prefix as the pathkeys as
+ * this increases the chances that an incremental sort will be able to be
+ * used by the upper planner.
*/
if (root->query_pathkeys)
{
+ int matches = 0;
+
foreach(lc, root->query_pathkeys)
{
PathKey *query_pathkey = (PathKey *) lfirst(lc);
@@ -1981,6 +1988,8 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
}
if (j >= necs)
break; /* didn't find match */
+
+ matches++;
}
/* if we got to the end of the list, we have them all */
if (lc == NULL)
@@ -2003,6 +2012,23 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
}
}
}
+
+ /*
+ * If we didn't match to all of the query_pathkeys, but did match to
+ * all of the join clauses then we'll make use of these as partially
+ * sorted input is better than nothing for the upper planner as it may
+ * lead to incremental sorts instead of full sorts.
+ */
+ else if (matches == nClauses)
+ {
+ pathkeys = list_copy_head(root->query_pathkeys, matches);
+
+ /* we have all of the join pathkeys, so nothing more to do */
+ pfree(ecs);
+ pfree(scores);
+
+ return pathkeys;
+ }
}
/*