Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Simplify LATERAL-related calculations within add_paths_to_joinrel().
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 9 Dec 2015 23:54:25 +0000 (18:54 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 9 Dec 2015 23:54:25 +0000 (18:54 -0500)
While convincing myself that commit 7e19db0c09719d79 would solve both of
the problems recently reported by Andreas Seltenreich, I realized that
add_paths_to_joinrel's handling of LATERAL restrictions could be made
noticeably simpler and faster if we were to retain the minimum possible
parameterization for each joinrel (that is, the set of relids supplying
unsatisfied lateral references in it).  We already retain that for
baserels, in RelOptInfo.lateral_relids, so we can use that field for
joinrels too.

This is a back-port of commit edca44b1525b3d591263d032dc4fe500ea771e0e.
I originally intended not to back-patch that, but additional hacking
in this area turns out to be needed, making it necessary not optional
to compute lateral_relids for joinrels.  In preparation for those fixes,
sync the relevant code with HEAD as much as practical.  (I did not risk
rearranging fields of RelOptInfo in released branches, however.)

src/backend/optimizer/path/joinpath.c
src/backend/optimizer/util/relnode.c
src/include/nodes/relation.h

index 1dc2e77598741383aab508d0c32c20eacfe3af4e..c0372780f0b743327e1539b7d72c70c6ce683929 100644 (file)
@@ -29,19 +29,19 @@ static void sort_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
                     RelOptInfo *outerrel, RelOptInfo *innerrel,
                     List *restrictlist, List *mergeclause_list,
                     JoinType jointype, SpecialJoinInfo *sjinfo,
-                    Relids param_source_rels, Relids extra_lateral_rels);
+                    Relids param_source_rels);
 static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel,
                     RelOptInfo *outerrel, RelOptInfo *innerrel,
                     List *restrictlist, List *mergeclause_list,
                     JoinType jointype, SpecialJoinInfo *sjinfo,
                     SemiAntiJoinFactors *semifactors,
-                    Relids param_source_rels, Relids extra_lateral_rels);
+                    Relids param_source_rels);
 static void hash_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel,
                     RelOptInfo *outerrel, RelOptInfo *innerrel,
                     List *restrictlist,
                     JoinType jointype, SpecialJoinInfo *sjinfo,
                     SemiAntiJoinFactors *semifactors,
-                    Relids param_source_rels, Relids extra_lateral_rels);
+                    Relids param_source_rels);
 static List *select_mergejoin_clauses(PlannerInfo *root,
                         RelOptInfo *joinrel,
                         RelOptInfo *outerrel,
@@ -87,7 +87,6 @@ add_paths_to_joinrel(PlannerInfo *root,
    bool        mergejoin_allowed = true;
    SemiAntiJoinFactors semifactors;
    Relids      param_source_rels = NULL;
-   Relids      extra_lateral_rels = NULL;
    ListCell   *lc;
 
    /*
@@ -153,59 +152,14 @@ add_paths_to_joinrel(PlannerInfo *root,
    }
 
    /*
-    * However, when a LATERAL subquery is involved, we have to be a bit
-    * laxer, because there will simply not be any paths for the joinrel that
-    * aren't parameterized by whatever the subquery is parameterized by,
-    * unless its parameterization is resolved within the joinrel.  Hence, add
-    * to param_source_rels anything that is laterally referenced in either
-    * input and is not in the join already.
+    * However, when a LATERAL subquery is involved, there will simply not be
+    * any paths for the joinrel that aren't parameterized by whatever the
+    * subquery is parameterized by, unless its parameterization is resolved
+    * within the joinrel.  So we might as well allow additional dependencies
+    * on whatever residual lateral dependencies the joinrel will have.
     */
-   foreach(lc, root->lateral_info_list)
-   {
-       LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(lc);
-
-       if (bms_is_subset(ljinfo->lateral_rhs, joinrel->relids))
-           param_source_rels = bms_join(param_source_rels,
-                                        bms_difference(ljinfo->lateral_lhs,
-                                                       joinrel->relids));
-   }
-
-   /*
-    * Another issue created by LATERAL references is that PlaceHolderVars
-    * that need to be computed at this join level might contain lateral
-    * references to rels not in the join, meaning that the paths for the join
-    * would need to be marked as parameterized by those rels, independently
-    * of all other considerations.  Set extra_lateral_rels to the set of such
-    * rels.  This will not affect our decisions as to which paths to
-    * generate; we merely add these rels to their required_outer sets.
-    */
-   foreach(lc, root->placeholder_list)
-   {
-       PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
-
-       /* PHVs without lateral refs can be skipped over quickly */
-       if (phinfo->ph_lateral == NULL)
-           continue;
-       /* Is it due to be evaluated at this join, and not in either input? */
-       if (bms_is_subset(phinfo->ph_eval_at, joinrel->relids) &&
-           !bms_is_subset(phinfo->ph_eval_at, outerrel->relids) &&
-           !bms_is_subset(phinfo->ph_eval_at, innerrel->relids))
-       {
-           /* Yes, remember its lateral rels */
-           extra_lateral_rels = bms_add_members(extra_lateral_rels,
-                                                phinfo->ph_lateral);
-       }
-   }
-
-   /*
-    * Make sure extra_lateral_rels doesn't list anything within the join, and
-    * that it's NULL if empty.  (This allows us to use bms_add_members to add
-    * it to required_outer below, while preserving the property that
-    * required_outer is exactly NULL if empty.)
-    */
-   extra_lateral_rels = bms_del_members(extra_lateral_rels, joinrel->relids);
-   if (bms_is_empty(extra_lateral_rels))
-       extra_lateral_rels = NULL;
+   param_source_rels = bms_add_members(param_source_rels,
+                                       joinrel->lateral_relids);
 
    /*
     * 1. Consider mergejoin paths where both relations must be explicitly
@@ -215,7 +169,7 @@ add_paths_to_joinrel(PlannerInfo *root,
        sort_inner_and_outer(root, joinrel, outerrel, innerrel,
                             restrictlist, mergeclause_list, jointype,
                             sjinfo,
-                            param_source_rels, extra_lateral_rels);
+                            param_source_rels);
 
    /*
     * 2. Consider paths where the outer relation need not be explicitly
@@ -228,7 +182,7 @@ add_paths_to_joinrel(PlannerInfo *root,
        match_unsorted_outer(root, joinrel, outerrel, innerrel,
                             restrictlist, mergeclause_list, jointype,
                             sjinfo, &semifactors,
-                            param_source_rels, extra_lateral_rels);
+                            param_source_rels);
 
 #ifdef NOT_USED
 
@@ -247,7 +201,7 @@ add_paths_to_joinrel(PlannerInfo *root,
        match_unsorted_inner(root, joinrel, outerrel, innerrel,
                             restrictlist, mergeclause_list, jointype,
                             sjinfo, &semifactors,
-                            param_source_rels, extra_lateral_rels);
+                            param_source_rels);
 #endif
 
    /*
@@ -259,7 +213,7 @@ add_paths_to_joinrel(PlannerInfo *root,
        hash_inner_and_outer(root, joinrel, outerrel, innerrel,
                             restrictlist, jointype,
                             sjinfo, &semifactors,
-                            param_source_rels, extra_lateral_rels);
+                            param_source_rels);
 }
 
 /*
@@ -353,7 +307,6 @@ try_nestloop_path(PlannerInfo *root,
                  SpecialJoinInfo *sjinfo,
                  SemiAntiJoinFactors *semifactors,
                  Relids param_source_rels,
-                 Relids extra_lateral_rels,
                  Path *outer_path,
                  Path *inner_path,
                  List *restrict_clauses,
@@ -382,9 +335,13 @@ try_nestloop_path(PlannerInfo *root,
 
    /*
     * Independently of that, add parameterization needed for any
-    * PlaceHolderVars that need to be computed at the join.
+    * PlaceHolderVars that need to be computed at the join.  We can handle
+    * that just by adding joinrel->lateral_relids; that might include some
+    * rels that are already in required_outer, but no harm done.  (Note that
+    * lateral_relids is exactly NULL if empty, so this will not break the
+    * property that required_outer is too.)
     */
-   required_outer = bms_add_members(required_outer, extra_lateral_rels);
+   required_outer = bms_add_members(required_outer, joinrel->lateral_relids);
 
    /*
     * Do a precheck to quickly eliminate obviously-inferior paths.  We
@@ -434,7 +391,6 @@ try_mergejoin_path(PlannerInfo *root,
                   JoinType jointype,
                   SpecialJoinInfo *sjinfo,
                   Relids param_source_rels,
-                  Relids extra_lateral_rels,
                   Path *outer_path,
                   Path *inner_path,
                   List *restrict_clauses,
@@ -464,7 +420,7 @@ try_mergejoin_path(PlannerInfo *root,
     * Independently of that, add parameterization needed for any
     * PlaceHolderVars that need to be computed at the join.
     */
-   required_outer = bms_add_members(required_outer, extra_lateral_rels);
+   required_outer = bms_add_members(required_outer, joinrel->lateral_relids);
 
    /*
     * If the given paths are already well enough ordered, we can skip doing
@@ -523,7 +479,6 @@ try_hashjoin_path(PlannerInfo *root,
                  SpecialJoinInfo *sjinfo,
                  SemiAntiJoinFactors *semifactors,
                  Relids param_source_rels,
-                 Relids extra_lateral_rels,
                  Path *outer_path,
                  Path *inner_path,
                  List *restrict_clauses,
@@ -550,7 +505,7 @@ try_hashjoin_path(PlannerInfo *root,
     * Independently of that, add parameterization needed for any
     * PlaceHolderVars that need to be computed at the join.
     */
-   required_outer = bms_add_members(required_outer, extra_lateral_rels);
+   required_outer = bms_add_members(required_outer, joinrel->lateral_relids);
 
    /*
     * See comments in try_nestloop_path().  Also note that hashjoin paths
@@ -630,7 +585,6 @@ clause_sides_match_join(RestrictInfo *rinfo, RelOptInfo *outerrel,
  * 'jointype' is the type of join to do
  * 'sjinfo' is extra info about the join for selectivity estimation
  * 'param_source_rels' are OK targets for parameterization of result paths
- * 'extra_lateral_rels' are additional parameterization for result paths
  */
 static void
 sort_inner_and_outer(PlannerInfo *root,
@@ -641,8 +595,7 @@ sort_inner_and_outer(PlannerInfo *root,
                     List *mergeclause_list,
                     JoinType jointype,
                     SpecialJoinInfo *sjinfo,
-                    Relids param_source_rels,
-                    Relids extra_lateral_rels)
+                    Relids param_source_rels)
 {
    Path       *outer_path;
    Path       *inner_path;
@@ -772,7 +725,6 @@ sort_inner_and_outer(PlannerInfo *root,
                           jointype,
                           sjinfo,
                           param_source_rels,
-                          extra_lateral_rels,
                           outer_path,
                           inner_path,
                           restrictlist,
@@ -818,7 +770,6 @@ sort_inner_and_outer(PlannerInfo *root,
  * 'sjinfo' is extra info about the join for selectivity estimation
  * 'semifactors' contains valid data if jointype is SEMI or ANTI
  * 'param_source_rels' are OK targets for parameterization of result paths
- * 'extra_lateral_rels' are additional parameterization for result paths
  */
 static void
 match_unsorted_outer(PlannerInfo *root,
@@ -830,8 +781,7 @@ match_unsorted_outer(PlannerInfo *root,
                     JoinType jointype,
                     SpecialJoinInfo *sjinfo,
                     SemiAntiJoinFactors *semifactors,
-                    Relids param_source_rels,
-                    Relids extra_lateral_rels)
+                    Relids param_source_rels)
 {
    JoinType    save_jointype = jointype;
    bool        nestjoinOK;
@@ -961,7 +911,6 @@ match_unsorted_outer(PlannerInfo *root,
                              sjinfo,
                              semifactors,
                              param_source_rels,
-                             extra_lateral_rels,
                              outerpath,
                              inner_cheapest_total,
                              restrictlist,
@@ -987,7 +936,6 @@ match_unsorted_outer(PlannerInfo *root,
                                  sjinfo,
                                  semifactors,
                                  param_source_rels,
-                                 extra_lateral_rels,
                                  outerpath,
                                  innerpath,
                                  restrictlist,
@@ -1002,7 +950,6 @@ match_unsorted_outer(PlannerInfo *root,
                                  sjinfo,
                                  semifactors,
                                  param_source_rels,
-                                 extra_lateral_rels,
                                  outerpath,
                                  matpath,
                                  restrictlist,
@@ -1058,7 +1005,6 @@ match_unsorted_outer(PlannerInfo *root,
                           jointype,
                           sjinfo,
                           param_source_rels,
-                          extra_lateral_rels,
                           outerpath,
                           inner_cheapest_total,
                           restrictlist,
@@ -1157,7 +1103,6 @@ match_unsorted_outer(PlannerInfo *root,
                                   jointype,
                                   sjinfo,
                                   param_source_rels,
-                                  extra_lateral_rels,
                                   outerpath,
                                   innerpath,
                                   restrictlist,
@@ -1203,7 +1148,6 @@ match_unsorted_outer(PlannerInfo *root,
                                       jointype,
                                       sjinfo,
                                       param_source_rels,
-                                      extra_lateral_rels,
                                       outerpath,
                                       innerpath,
                                       restrictlist,
@@ -1238,7 +1182,6 @@ match_unsorted_outer(PlannerInfo *root,
  * 'sjinfo' is extra info about the join for selectivity estimation
  * 'semifactors' contains valid data if jointype is SEMI or ANTI
  * 'param_source_rels' are OK targets for parameterization of result paths
- * 'extra_lateral_rels' are additional parameterization for result paths
  */
 static void
 hash_inner_and_outer(PlannerInfo *root,
@@ -1249,8 +1192,7 @@ hash_inner_and_outer(PlannerInfo *root,
                     JoinType jointype,
                     SpecialJoinInfo *sjinfo,
                     SemiAntiJoinFactors *semifactors,
-                    Relids param_source_rels,
-                    Relids extra_lateral_rels)
+                    Relids param_source_rels)
 {
    bool        isouterjoin = IS_OUTER_JOIN(jointype);
    List       *hashclauses;
@@ -1324,7 +1266,6 @@ hash_inner_and_outer(PlannerInfo *root,
                              sjinfo,
                              semifactors,
                              param_source_rels,
-                             extra_lateral_rels,
                              cheapest_total_outer,
                              cheapest_total_inner,
                              restrictlist,
@@ -1344,7 +1285,6 @@ hash_inner_and_outer(PlannerInfo *root,
                              sjinfo,
                              semifactors,
                              param_source_rels,
-                             extra_lateral_rels,
                              cheapest_total_outer,
                              cheapest_total_inner,
                              restrictlist,
@@ -1357,7 +1297,6 @@ hash_inner_and_outer(PlannerInfo *root,
                                  sjinfo,
                                  semifactors,
                                  param_source_rels,
-                                 extra_lateral_rels,
                                  cheapest_startup_outer,
                                  cheapest_total_inner,
                                  restrictlist,
@@ -1382,7 +1321,6 @@ hash_inner_and_outer(PlannerInfo *root,
                                  sjinfo,
                                  semifactors,
                                  param_source_rels,
-                                 extra_lateral_rels,
                                  cheapest_startup_outer,
                                  cheapest_total_inner,
                                  restrictlist,
@@ -1420,7 +1358,6 @@ hash_inner_and_outer(PlannerInfo *root,
                                      sjinfo,
                                      semifactors,
                                      param_source_rels,
-                                     extra_lateral_rels,
                                      outerpath,
                                      innerpath,
                                      restrictlist,
index fab5cd4d8b9df3fb762039fa1b64efad41caa9a2..79842bbdaca33389e26566958304fd294eb9effa 100644 (file)
@@ -376,7 +376,7 @@ build_join_rel(PlannerInfo *root,
    joinrel->attr_needed = NULL;
    joinrel->attr_widths = NULL;
    joinrel->lateral_vars = NIL;
-   joinrel->lateral_relids = NULL;
+   joinrel->lateral_relids = min_join_parameterization(root, joinrel->relids);
    joinrel->lateral_referencers = NULL;
    joinrel->indexlist = NIL;
    joinrel->pages = 0;
index d5513ffb316319f5889bd922b41dff808ac9be6a..1cbc6b2ea9a7bd0c62cd9bc17a092e48e44d7cc8 100644 (file)
@@ -349,7 +349,7 @@ typedef struct PlannerInfo
  *     lateral_vars - lateral cross-references of rel, if any (list of
  *                    Vars and PlaceHolderVars)
  *     lateral_relids - required outer rels for LATERAL, as a Relids set
- *                      (for child rels this can be more than lateral_vars)
+ *         (this is now used for join rels too, but we won't move it till 9.5)
  *     lateral_referencers - relids of rels that reference this one laterally
  *     indexlist - list of IndexOptInfo nodes for relation's indexes
  *                 (always NIL if it's not a table)
@@ -368,7 +368,7 @@ typedef struct PlannerInfo
  *     and fdw_private are filled during initial path creation.
  *
  *     For otherrels that are appendrel members, these fields are filled
- *     in just as for a baserel.
+ *     in just as for a baserel, except we don't bother with lateral_vars.
  *
  * The presence of the remaining fields depends on the restrictions
  * and joins that the relation participates in: