From: Tom Lane Date: Sat, 27 Oct 2007 05:45:43 +0000 (+0000) Subject: Avoid considering both sort directions as equally useful for merging. X-Git-Tag: REL8_3_BETA3~181 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=834ddc6272943ed7075cbca9646fdacb3598a93d;p=postgresql Avoid considering both sort directions as equally useful for merging. This doubles the planning workload for mergejoins while not actually accomplishing much. The only useful case is where one of the directions matches the query's ORDER BY request; therefore, put a thumb on the scales in that direction, and otherwise arbitrarily consider only the ASC direction. (This is a lot easier now than it would've been before 8.3, since we have more semantic knowledge embedded in PathKeys now.) --- diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index a110fa947b..b48bd95389 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -11,7 +11,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.85 2007/05/31 16:57:34 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.86 2007/10/27 05:45:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,6 +49,7 @@ static PathKey *make_pathkey_from_sortinfo(PlannerInfo *root, bool canonicalize); static Var *find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, AttrNumber varattno); +static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey); /**************************************************************************** @@ -1242,6 +1243,13 @@ make_inner_pathkeys_for_merge(PlannerInfo *root, * overoptimistic, since joinclauses that require different other relations * might never be usable at the same time, but trying to be exact is likely * to be more trouble than it's worth. + * + * To avoid doubling the number of mergejoin paths considered, we would like + * to consider only one of the two scan directions (ASC or DESC) as useful + * for merging for any given target column. The choice is arbitrary unless + * one of the directions happens to match an ORDER BY key, in which case + * that direction should be preferred, in hopes of avoiding a final sort step. + * right_merge_direction() implements this heuristic. */ int pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys) @@ -1255,6 +1263,10 @@ pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys) bool matched = false; ListCell *j; + /* If "wrong" direction, not useful for merging */ + if (!right_merge_direction(root, pathkey)) + break; + /* * First look into the EquivalenceClass of the pathkey, to see if * there are any members not yet joined to the rel. If so, it's @@ -1301,6 +1313,38 @@ pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys) return useful; } +/* + * right_merge_direction + * Check whether the pathkey embodies the preferred sort direction + * for merging its target column. + */ +static bool +right_merge_direction(PlannerInfo *root, PathKey *pathkey) +{ + ListCell *l; + + foreach(l, root->query_pathkeys) + { + PathKey *query_pathkey = (PathKey *) lfirst(l); + + if (pathkey->pk_eclass == query_pathkey->pk_eclass && + pathkey->pk_opfamily == query_pathkey->pk_opfamily) + { + /* + * Found a matching query sort column. Prefer this pathkey's + * direction iff it matches. Note that we ignore pk_nulls_first, + * which means that a sort might be needed anyway ... but we + * still want to prefer only one of the two possible directions, + * and we might as well use this one. + */ + return (pathkey->pk_strategy == query_pathkey->pk_strategy); + } + } + + /* If no matching ORDER BY request, prefer the ASC direction */ + return (pathkey->pk_strategy == BTLessStrategyNumber); +} + /* * pathkeys_useful_for_ordering * Count the number of pathkeys that are useful for meeting the