diff options
Diffstat (limited to 'src/backend/optimizer/path/pathkeys.c')
-rw-r--r-- | src/backend/optimizer/path/pathkeys.c | 40 |
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; + } } /* |