Tighten coding in new_join_pathkey, which seems to be a hotspot
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 May 1999 00:26:33 +0000 (00:26 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 17 May 1999 00:26:33 +0000 (00:26 +0000)
for GEQO ...

src/backend/optimizer/path/pathkeys.c

index 1cde4a686cfbcce987b676543a50f8e4f646ebc5..09a5b8a51f17aeef65d63250eee0f1c4c0e47d18 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.8 1999/04/30 03:59:06 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.9 1999/05/17 00:26:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,30 +29,34 @@ static int match_pathkey_joinkeys(List *pathkey, List *joinkeys,
                                                int outer_or_inner);
 static List *new_join_pathkey(List *pathkeys, List *join_rel_tlist,
                                                          List *joinclauses);
-static List *get_joinvars_for_var(Var *pathkey, List **considered_pathkeys,
-                                               List *join_rel_tlist, List *joinclauses);
 
 
-/*
+/*--------------------
  *     Explanation of Path.pathkeys
  *
  *     Path.pathkeys is a List of List of Var nodes that represent the sort
  *     order of the result generated by the Path.
  *
  *     In single/base relation RelOptInfo's, the Path's represent various ways
- *     of generate the relation.  Sequential scan Paths have a NIL pathkeys.
- *     Index scans have Path.pathkeys that represent the chosen index.  A
- *     single-key index pathkeys would be { {tab1_indexkey1} }.  The pathkeys
- *     entry for a multi-key index would be { {tab1_indexkey1}, {tab1_indexkey2} }.
+ *     of generating the relation and the resulting ordering of the tuples.
+ *     Sequential scan Paths have NIL pathkeys, indicating no known ordering.
+ *     Index scans have Path.pathkeys that represent the chosen index.
+ *     A single-key index pathkeys would be { {tab1_indexkey1} }.  For a
+ *     multi-key index pathkeys would be { {tab1_indexkey1}, {tab1_indexkey2} },
+ *     indicating major sort by indexkey1 and minor sort by indexkey2.
  *
  *     Multi-relation RelOptInfo Path's are more complicated.  Mergejoins are
- *     only performed with equajoins("=").  Because of this, the multi-relation
+ *     only performed with equijoins ("=").  Because of this, the multi-relation
  *     path actually has more than one primary Var key.  For example, a
  *     mergejoin Path of "tab1.col1 = tab2.col1" would generate a pathkeys of
- *     { {tab1.col1, tab2.col1} }.  This allows future joins to use either Var
- *     as a pre-sorted key to prevent Mergejoins from having to re-sort the Path.
- *     They are equal, so they are both primary sort keys.  This is why pathkeys
- *     is a List of Lists.
+ *     { {tab1.col1, tab2.col1} }, indicating that the major sort order of the
+ *     Path can be taken to be *either* tab1.col1 or tab2.col1.
+ *     They are equal, so they are both primary sort keys.  This allows future
+ *     joins to use either Var as a pre-sorted key to prevent upper Mergejoins
+ *     from having to re-sort the Path.  This is why pathkeys is a List of Lists.
+ *
+ *     Note that while the order of the top list is meaningful (primary vs.
+ *     secondary sort key), the order of each sublist is arbitrary.
  *
  *     For multi-key sorts, if the outer is sorted by a multi-key index, the
  *     multi-key index remains after the join.  If the inner has a multi-key
@@ -60,11 +64,16 @@ static List *get_joinvars_for_var(Var *pathkey, List **considered_pathkeys,
  *     Mergejoins only join on the primary key.  Currently, non-primary keys
  *     in the pathkeys List are of limited value.
  *
- *     HashJoin has similar functionality.  NestJoin does not perform sorting,
- *     and allows non-equajoins, so it does not allow useful pathkeys.
+ *     Although Hashjoins also work only with equijoin operators, it is *not*
+ *     safe to consider the output of a Hashjoin to be sorted in any particular
+ *     order --- not even the outer path's order.  This is true because the
+ *     executor might have to split the join into multiple batches.
+ *
+ *     NestJoin does not perform sorting, and allows non-equijoins, so it does
+ *     not allow useful pathkeys.  (But couldn't we use the outer path's order?)
  *
  *     -- bjm
- *     
+ *--------------------
  */
  
 /****************************************************************************
@@ -228,7 +237,7 @@ get_cheapest_path_for_joinkeys(List *joinkeys,
                                                                 int outer_or_inner)
 {
        Path       *matched_path = NULL;
-       List       *i = NIL;
+       List       *i;
 
        foreach(i, paths)
        {
@@ -337,16 +346,16 @@ new_join_pathkeys(List *outer_pathkeys,
                                  List *join_rel_tlist,
                                  List *joinclauses)
 {
-       List       *outer_pathkey = NIL;
        List       *final_pathkeys = NIL;
-       List       *new_pathkey;
-       List       *i = NIL;
+       List       *i;
 
        foreach(i, outer_pathkeys)
        {
-               outer_pathkey = lfirst(i);
+               List       *outer_pathkey = lfirst(i);
+               List       *new_pathkey;
+
                new_pathkey = new_join_pathkey(outer_pathkey, join_rel_tlist,
-                                                                               joinclauses);
+                                                                          joinclauses);
                if (new_pathkey != NIL)
                        final_pathkeys = lappend(final_pathkeys, new_pathkey);
        }
@@ -355,19 +364,18 @@ new_join_pathkeys(List *outer_pathkeys,
 
 /*
  * new_join_pathkey
- *       Finds new vars that become pathkeys due to qualification clauses that
- *       contain any previously considered pathkeys.  These new pathkeys plus the
- *       pathkeys from 'pathkeys' form a new pathkey for the join relation.
+ *       Generate an individual pathkey sublist, consisting of the outer vars
+ *       already mentioned in 'pathkey' plus any inner vars that are joined to
+ *       them (and thus can now also be considered path keys, per discussion
+ *       at the top of this file).
  *
  *       Note that each returned pathkey is the var node found in
  *       'join_rel_tlist' rather than the joinclause var node.
+ *       (Is this important?)  Also, we return a fully copied list
+ *       that does not share any subnodes with existing data structures.
+ *       (Is that important, either?)
  *
- * 'pathkeys' is a list of pathkeys for which matching pathkeys are to be
- *             found
- * 'considered_pathkeys' is the current list of all pathkeys corresponding
- *             to a given pathkey
- *
- * Returns a new pathkey(list of pathkeys).
+ * Returns a new pathkey (list of pathkey variables).
  *
  */
 static List *
@@ -375,84 +383,33 @@ new_join_pathkey(List *pathkey,
                                 List *join_rel_tlist,
                                 List *joinclauses)
 {
-       List       *final_pathkey = NIL;
-       List       *i = NIL;
-       List       *considered_pathkeys = NIL;
+       List       *new_pathkey = NIL;
+       List       *i,
+                          *j;
 
        foreach(i, pathkey)
        {
                Var                *key = (Var *) lfirst(i);
-               List       *joined_keys;
                Expr       *tlist_key;
 
                Assert(key);
-               joined_keys = get_joinvars_for_var(key, &considered_pathkeys,
-                                                                               join_rel_tlist, joinclauses);
-               if (joined_keys)
-               {
-                       considered_pathkeys =  nconc(considered_pathkeys, joined_keys);
-                       final_pathkey = nconc(final_pathkey, joined_keys);
-               }
                                                                        
                tlist_key = matching_tlist_var(key, join_rel_tlist);
-               if (tlist_key && !member(tlist_key, considered_pathkeys))
-               {
-                       /*
-                        *      If pathkey is in the target list, and not considered,
-                        *      add it
-                        */
-                       considered_pathkeys =  lcons(tlist_key, considered_pathkeys);
-                       final_pathkey = lcons(tlist_key, final_pathkey);
-               }
-       }
-       return copyObject(final_pathkey);
-}
+               if (tlist_key && !member(tlist_key, new_pathkey))
+                       new_pathkey = lcons(copyObject(tlist_key), new_pathkey);
 
-/*
- * get_joinvars_for_var
- *       Returns a list of new pathkeys:
- *       (1) which are not listed in 'considered_pathkeys'
- *       (2) for which the "other" variable in some clause in 'joinclauses' is
- *               'pathkey'
- *       (3) which are mentioned in 'join_rel_tlist'
- *
- *       Note that each returned pathkey is the var node found in
- *       'join_rel_tlist' rather than the joinclause var node.
- *
- * 'pathkey' is the var node for which we are trying to find matching
- *             clauses
- *
- * Returns a list of new pathkeys.
- *
- */
-static List *
-get_joinvars_for_var(Var *key,
-                                        List **considered_pathkeys,
-                                        List *join_rel_tlist,
-                                        List *joinclauses)
-{
-       List       *final_pathkey = NIL;
-       Expr       *joinclause;
-       List       *i;
-       Expr       *tlist_other_var;
-
-       foreach(i, joinclauses)
-       {
-               joinclause = lfirst(i);
+               foreach(j, joinclauses)
+               {
+                       Expr       *joinclause = lfirst(j);
+                       Expr       *tlist_other_var;
 
-               tlist_other_var = matching_tlist_var(
+                       tlist_other_var = matching_tlist_var(
                                                                other_join_clause_var(key, joinclause),
                                                                join_rel_tlist);
-               if (tlist_other_var &&
-                       !member(tlist_other_var, *considered_pathkeys))
-               {
-                       /*
-                        *      The key has a join variable that is in the target list,
-                        *      and has not been considered.
-                        */
-                       *considered_pathkeys = lcons(tlist_other_var, *considered_pathkeys);
-                       final_pathkey = lcons(tlist_other_var, final_pathkey);
+                       if (tlist_other_var && !member(tlist_other_var, new_pathkey))
+                               new_pathkey = lcons(copyObject(tlist_other_var), new_pathkey);
                }
        }
-       return final_pathkey;
+
+       return new_pathkey;
 }