Improve performance of adjust_appendrel_attrs_multilevel.
authorTom Lane <[email protected]>
Thu, 18 Aug 2022 16:36:06 +0000 (12:36 -0400)
committerTom Lane <[email protected]>
Thu, 18 Aug 2022 16:36:16 +0000 (12:36 -0400)
The present implementations of adjust_appendrel_attrs_multilevel and
its sibling adjust_child_relids_multilevel are very messy, because
they work by reconstructing the relids of the child's immediate
parent and then seeing if that's bms_equal to the relids of the
target parent.  Aside from being quite inefficient, this will not
work with planned future changes to make joinrels' relid sets
contain outer-join relids in addition to baserels.

The whole thing can be solved at a stroke by adding explicit parent
and top_parent links to child RelOptInfos, and making these functions
work with RelOptInfo pointers instead of relids.  Doing that is
simpler for most callers, too.

In my original version of this patch, I got rid of
RelOptInfo.top_parent_relids on the grounds that it was now redundant.
However, that adds a lot of code churn in places that otherwise would
not need changing, and arguably the extra indirection needed to fetch
top_parent->relids in those places costs something.  So this version
leaves that field in place.

Discussion: https://postgr.es/m/553080.1657481916@sss.pgh.pa.us

src/backend/optimizer/path/equivclass.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/util/appendinfo.c
src/backend/optimizer/util/pathnode.c
src/backend/optimizer/util/relnode.c
src/backend/partitioning/partprune.c
src/include/nodes/pathnodes.h
src/include/optimizer/appendinfo.h

index 2c900e6b120c87ad7ba2f1122bdd32573354380e..799bdc91d095707f02d5e7004bbf39a2ad3ed93b 100644 (file)
@@ -1760,8 +1760,8 @@ generate_join_implied_equalities_broken(PlannerInfo *root,
    if (IS_OTHER_REL(inner_rel) && result != NIL)
        result = (List *) adjust_appendrel_attrs_multilevel(root,
                                                            (Node *) result,
-                                                           inner_rel->relids,
-                                                           inner_rel->top_parent_relids);
+                                                           inner_rel,
+                                                           inner_rel->top_parent);
 
    return result;
 }
@@ -2626,8 +2626,8 @@ add_child_rel_equivalences(PlannerInfo *root,
                    child_expr = (Expr *)
                        adjust_appendrel_attrs_multilevel(root,
                                                          (Node *) cur_em->em_expr,
-                                                         child_relids,
-                                                         top_parent_relids);
+                                                         child_rel,
+                                                         child_rel->top_parent);
                }
 
                /*
@@ -2768,8 +2768,8 @@ add_child_join_rel_equivalences(PlannerInfo *root,
                    child_expr = (Expr *)
                        adjust_appendrel_attrs_multilevel(root,
                                                          (Node *) cur_em->em_expr,
-                                                         child_relids,
-                                                         top_parent_relids);
+                                                         child_joinrel,
+                                                         child_joinrel->top_parent);
                }
 
                /*
@@ -2791,8 +2791,8 @@ add_child_join_rel_equivalences(PlannerInfo *root,
                    new_nullable_relids =
                        adjust_child_relids_multilevel(root,
                                                       new_nullable_relids,
-                                                      child_relids,
-                                                      top_parent_relids);
+                                                      child_joinrel,
+                                                      child_joinrel->top_parent);
 
                (void) add_eq_member(cur_ec, child_expr,
                                     new_relids, new_nullable_relids,
index b781080dbac26f5be370d8895d1a4b90351239e3..cf9e0a74dbf38fbc9825319de2cddb2eed1e7f31 100644 (file)
@@ -1793,8 +1793,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                            withCheckOptions = (List *)
                                adjust_appendrel_attrs_multilevel(root,
                                                                  (Node *) withCheckOptions,
-                                                                 this_result_rel->relids,
-                                                                 top_result_rel->relids);
+                                                                 this_result_rel,
+                                                                 top_result_rel);
                        withCheckOptionLists = lappend(withCheckOptionLists,
                                                       withCheckOptions);
                    }
@@ -1806,8 +1806,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                            returningList = (List *)
                                adjust_appendrel_attrs_multilevel(root,
                                                                  (Node *) returningList,
-                                                                 this_result_rel->relids,
-                                                                 top_result_rel->relids);
+                                                                 this_result_rel,
+                                                                 top_result_rel);
                        returningLists = lappend(returningLists,
                                                 returningList);
                    }
@@ -1828,13 +1828,13 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                            leaf_action->qual =
                                adjust_appendrel_attrs_multilevel(root,
                                                                  (Node *) action->qual,
-                                                                 this_result_rel->relids,
-                                                                 top_result_rel->relids);
+                                                                 this_result_rel,
+                                                                 top_result_rel);
                            leaf_action->targetList = (List *)
                                adjust_appendrel_attrs_multilevel(root,
                                                                  (Node *) action->targetList,
-                                                                 this_result_rel->relids,
-                                                                 top_result_rel->relids);
+                                                                 this_result_rel,
+                                                                 top_result_rel);
                            if (leaf_action->commandType == CMD_UPDATE)
                                leaf_action->updateColnos =
                                    adjust_inherited_attnums_multilevel(root,
index 9d4bb4702700c6e36d2013b5600c0661e530d1c5..62cccf9d87cbdb428847cfc6a8c32baf519dca84 100644 (file)
@@ -479,39 +479,34 @@ adjust_appendrel_attrs_mutator(Node *node,
 
 /*
  * adjust_appendrel_attrs_multilevel
- *   Apply Var translations from a toplevel appendrel parent down to a child.
+ *   Apply Var translations from an appendrel parent down to a child.
  *
- * In some cases we need to translate expressions referencing a parent relation
- * to reference an appendrel child that's multiple levels removed from it.
+ * Replace Vars in the "node" expression that reference "parentrel" with
+ * the appropriate Vars for "childrel".  childrel can be more than one
+ * inheritance level removed from parentrel.
  */
 Node *
 adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
-                                 Relids child_relids,
-                                 Relids top_parent_relids)
+                                 RelOptInfo *childrel,
+                                 RelOptInfo *parentrel)
 {
    AppendRelInfo **appinfos;
-   Bitmapset  *parent_relids = NULL;
    int         nappinfos;
-   int         cnt;
-
-   Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
-
-   appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
 
-   /* Construct relids set for the immediate parent of given child. */
-   for (cnt = 0; cnt < nappinfos; cnt++)
+   /* Recurse if immediate parent is not the top parent. */
+   if (childrel->parent != parentrel)
    {
-       AppendRelInfo *appinfo = appinfos[cnt];
-
-       parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
+       if (childrel->parent)
+           node = adjust_appendrel_attrs_multilevel(root, node,
+                                                    childrel->parent,
+                                                    parentrel);
+       else
+           elog(ERROR, "childrel is not a child of parentrel");
    }
 
-   /* Recurse if immediate parent is not the top parent. */
-   if (!bms_equal(parent_relids, top_parent_relids))
-       node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
-                                                top_parent_relids);
+   /* Now translate for this child. */
+   appinfos = find_appinfos_by_relids(root, childrel->relids, &nappinfos);
 
-   /* Now translate for this child */
    node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
 
    pfree(appinfos);
@@ -554,56 +549,43 @@ adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
 }
 
 /*
- * Replace any relid present in top_parent_relids with its child in
- * child_relids. Members of child_relids can be multiple levels below top
- * parent in the partition hierarchy.
+ * Substitute child's relids for parent's relids in a Relid set.
+ * The childrel can be multiple inheritance levels below the parent.
  */
 Relids
 adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
-                              Relids child_relids, Relids top_parent_relids)
+                              RelOptInfo *childrel,
+                              RelOptInfo *parentrel)
 {
    AppendRelInfo **appinfos;
    int         nappinfos;
-   Relids      parent_relids = NULL;
-   Relids      result;
-   Relids      tmp_result = NULL;
-   int         cnt;
 
    /*
-    * If the given relids set doesn't contain any of the top parent relids,
-    * it will remain unchanged.
+    * If the given relids set doesn't contain any of the parent relids, it
+    * will remain unchanged.
     */
-   if (!bms_overlap(relids, top_parent_relids))
+   if (!bms_overlap(relids, parentrel->relids))
        return relids;
 
-   appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
-
-   /* Construct relids set for the immediate parent of the given child. */
-   for (cnt = 0; cnt < nappinfos; cnt++)
-   {
-       AppendRelInfo *appinfo = appinfos[cnt];
-
-       parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
-   }
-
    /* Recurse if immediate parent is not the top parent. */
-   if (!bms_equal(parent_relids, top_parent_relids))
+   if (childrel->parent != parentrel)
    {
-       tmp_result = adjust_child_relids_multilevel(root, relids,
-                                                   parent_relids,
-                                                   top_parent_relids);
-       relids = tmp_result;
+       if (childrel->parent)
+           relids = adjust_child_relids_multilevel(root, relids,
+                                                   childrel->parent,
+                                                   parentrel);
+       else
+           elog(ERROR, "childrel is not a child of parentrel");
    }
 
-   result = adjust_child_relids(relids, nappinfos, appinfos);
+   /* Now translate for this child. */
+   appinfos = find_appinfos_by_relids(root, childrel->relids, &nappinfos);
+
+   relids = adjust_child_relids(relids, nappinfos, appinfos);
 
-   /* Free memory consumed by any intermediate result. */
-   if (tmp_result)
-       bms_free(tmp_result);
-   bms_free(parent_relids);
    pfree(appinfos);
 
-   return result;
+   return relids;
 }
 
 /*
@@ -694,8 +676,8 @@ get_translated_update_targetlist(PlannerInfo *root, Index relid,
        *processed_tlist = (List *)
            adjust_appendrel_attrs_multilevel(root,
                                              (Node *) root->processed_tlist,
-                                             bms_make_singleton(relid),
-                                             bms_make_singleton(root->parse->resultRelation));
+                                             find_base_rel(root, relid),
+                                             find_base_rel(root, root->parse->resultRelation));
        if (update_colnos)
            *update_colnos =
                adjust_inherited_attnums_multilevel(root, root->update_colnos,
index dd64b460865d8e45a3407fb60eb4778a7213fcc2..e10561d843ae8a7ee92ff60d253b51dbac6246a3 100644 (file)
@@ -4026,8 +4026,8 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
 #define ADJUST_CHILD_ATTRS(node) \
    ((node) = \
     (List *) adjust_appendrel_attrs_multilevel(root, (Node *) (node), \
-                                               child_rel->relids, \
-                                               child_rel->top_parent_relids))
+                                               child_rel, \
+                                               child_rel->top_parent))
 
 #define REPARAMETERIZE_CHILD_PATH(path) \
 do { \
@@ -4244,8 +4244,8 @@ do { \
    old_ppi = new_path->param_info;
    required_outer =
        adjust_child_relids_multilevel(root, old_ppi->ppi_req_outer,
-                                      child_rel->relids,
-                                      child_rel->top_parent_relids);
+                                      child_rel,
+                                      child_rel->top_parent);
 
    /* If we already have a PPI for this parameterization, just return it */
    new_ppi = find_param_path_info(new_path->parent, required_outer);
index 965eb5b3b45268dcf88ef837e396352a89332b69..edcdd0a3603a53e9c2455e4ca2866ac68b14eae5 100644 (file)
@@ -265,14 +265,10 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
     */
    if (parent)
    {
-       /*
-        * Each direct or indirect child wants to know the relids of its
-        * topmost parent.
-        */
-       if (parent->top_parent_relids)
-           rel->top_parent_relids = parent->top_parent_relids;
-       else
-           rel->top_parent_relids = bms_copy(parent->relids);
+       /* We keep back-links to immediate parent and topmost parent. */
+       rel->parent = parent;
+       rel->top_parent = parent->top_parent ? parent->top_parent : parent;
+       rel->top_parent_relids = rel->top_parent->relids;
 
        /*
         * Also propagate lateral-reference information from appendrel parent
@@ -294,6 +290,8 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
    }
    else
    {
+       rel->parent = NULL;
+       rel->top_parent = NULL;
        rel->top_parent_relids = NULL;
        rel->direct_lateral_relids = NULL;
        rel->lateral_relids = NULL;
@@ -663,6 +661,8 @@ build_join_rel(PlannerInfo *root,
    joinrel->joininfo = NIL;
    joinrel->has_eclass_joins = false;
    joinrel->consider_partitionwise_join = false;   /* might get changed later */
+   joinrel->parent = NULL;
+   joinrel->top_parent = NULL;
    joinrel->top_parent_relids = NULL;
    joinrel->part_scheme = NULL;
    joinrel->nparts = -1;
@@ -843,7 +843,9 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
    joinrel->joininfo = NIL;
    joinrel->has_eclass_joins = false;
    joinrel->consider_partitionwise_join = false;   /* might get changed later */
-   joinrel->top_parent_relids = NULL;
+   joinrel->parent = parent_joinrel;
+   joinrel->top_parent = parent_joinrel->top_parent ? parent_joinrel->top_parent : parent_joinrel;
+   joinrel->top_parent_relids = joinrel->top_parent->relids;
    joinrel->part_scheme = NULL;
    joinrel->nparts = -1;
    joinrel->boundinfo = NULL;
@@ -855,9 +857,6 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
    joinrel->partexprs = NULL;
    joinrel->nullable_partexprs = NULL;
 
-   joinrel->top_parent_relids = bms_union(outer_rel->top_parent_relids,
-                                          inner_rel->top_parent_relids);
-
    /* Compute information relevant to foreign relations. */
    set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
 
index fc19232c7b92637506a752e1d82a399fc62fa880..bf9fe5b7aafe2284361e051b00bf34d20df0a47d 100644 (file)
@@ -529,8 +529,8 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
            partprunequal = (List *)
                adjust_appendrel_attrs_multilevel(root,
                                                  (Node *) prunequal,
-                                                 subpart->relids,
-                                                 targetpart->relids);
+                                                 subpart,
+                                                 targetpart);
        }
 
        /*
index bdc7b50db9757acf8834f1f5940580809d10555c..294cfe9c47c96159fe2a42dfb0dd31b6fe9463b1 100644 (file)
@@ -938,7 +938,15 @@ typedef struct RelOptInfo
     */
    /* consider partitionwise join paths? (if partitioned rel) */
    bool        consider_partitionwise_join;
-   /* Relids of topmost parents (if "other" rel) */
+
+   /*
+    * inheritance links, if this is an otherrel (otherwise NULL):
+    */
+   /* Immediate parent relation (dumping it would be too verbose) */
+   struct RelOptInfo *parent pg_node_attr(read_write_ignore);
+   /* Topmost parent relation (dumping it would be too verbose) */
+   struct RelOptInfo *top_parent pg_node_attr(read_write_ignore);
+   /* Relids of topmost parent (redundant, but handy) */
    Relids      top_parent_relids;
 
    /*
index fc808dcd27650ec71590a7435302e42b52aec542..5e80a741a42ba8d709339f19eeca4b2ac29c2f1b 100644 (file)
@@ -23,13 +23,13 @@ extern AppendRelInfo *make_append_rel_info(Relation parentrel,
 extern Node *adjust_appendrel_attrs(PlannerInfo *root, Node *node,
                                    int nappinfos, AppendRelInfo **appinfos);
 extern Node *adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
-                                              Relids child_relids,
-                                              Relids top_parent_relids);
+                                              RelOptInfo *childrel,
+                                              RelOptInfo *parentrel);
 extern Relids adjust_child_relids(Relids relids, int nappinfos,
                                  AppendRelInfo **appinfos);
 extern Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
-                                            Relids child_relids,
-                                            Relids top_parent_relids);
+                                            RelOptInfo *childrel,
+                                            RelOptInfo *parentrel);
 extern List *adjust_inherited_attnums(List *attnums, AppendRelInfo *context);
 extern List *adjust_inherited_attnums_multilevel(PlannerInfo *root,
                                                 List *attnums,