Avoid considering both sort directions as equally useful for merging.
authorTom Lane
Sat, 27 Oct 2007 05:45:43 +0000 (05:45 +0000)
committerTom Lane
Sat, 27 Oct 2007 05:45:43 +0000 (05:45 +0000)
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.)

src/backend/optimizer/path/pathkeys.c

index a110fa947b1421207f3c5cf1e7f047fb8a56c803..b48bd953894bc2f79375471ee3b1a3f4ef14287a 100644 (file)
@@ -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