]> granicus.if.org Git - postgresql/commitdiff
Avoid considering both sort directions as equally useful for merging.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 27 Oct 2007 05:45:43 +0000 (05:45 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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