v26-0001-Build-other-rels-of-appendrel-baserels-in-a-sepa.patch
text/plain
Filename: v26-0001-Build-other-rels-of-appendrel-baserels-in-a-sepa.patch
Type: text/plain
Part: 0
Patch
Format: format-patch
Series: patch v26-0001
Subject: Build "other rels" of appendrel baserels in a separate step
| File | + | − |
|---|---|---|
| src/backend/optimizer/path/allpaths.c | 1 | 1 |
| src/backend/optimizer/plan/initsplan.c | 49 | 4 |
| src/backend/optimizer/plan/planmain.c | 11 | 4 |
| src/backend/optimizer/util/relnode.c | 76 | 42 |
| src/include/optimizer/pathnode.h | 2 | 0 |
| src/include/optimizer/planmain.h | 1 | 0 |
From 1d83debe07040a93721f17785d075d26dab6f088 Mon Sep 17 00:00:00 2001
From: Amit <amitlangote09@gmail.com>
Date: Sat, 2 Mar 2019 14:13:13 +0900
Subject: [PATCH v26 1/6] Build "other rels" of appendrel baserels in a
separate step
add_other_rels_to_query() runs after query_planner has distributed
restrict clauses to base relations. This will allow us to use
the clauses applied a given partitioned baserel to perform partition
pruning, and add other rels for only the unpruned partiitons.
---
src/backend/optimizer/path/allpaths.c | 2 +-
src/backend/optimizer/plan/initsplan.c | 53 +++++++++++++--
src/backend/optimizer/plan/planmain.c | 15 +++--
src/backend/optimizer/util/relnode.c | 118 +++++++++++++++++++++------------
src/include/optimizer/pathnode.h | 2 +
src/include/optimizer/planmain.h | 1 +
6 files changed, 140 insertions(+), 51 deletions(-)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 0debac75c6..8d8a8f17d5 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1028,7 +1028,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
/*
* The child rel's RelOptInfo was already created during
- * add_base_rels_to_query.
+ * add_other_rels_to_query.
*/
childrel = find_base_rel(root, childRTindex);
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 2afc3f1dfe..54fc4dda97 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -20,6 +20,7 @@
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
+#include "optimizer/inherit.h"
#include "optimizer/joininfo.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
@@ -30,6 +31,7 @@
#include "optimizer/prep.h"
#include "optimizer/restrictinfo.h"
#include "parser/analyze.h"
+#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
#include "utils/lsyscache.h"
@@ -97,10 +99,11 @@ static void check_hashjoinable(RestrictInfo *restrictinfo);
* jtnode. Internally, the function recurses through the jointree.
*
* At the end of this process, there should be one baserel RelOptInfo for
- * every non-join RTE that is used in the query. Therefore, this routine
- * is the only place that should call build_simple_rel with reloptkind
- * RELOPT_BASEREL. (Note: build_simple_rel recurses internally to build
- * "other rel" RelOptInfos for the members of any appendrels we find here.)
+ * every non-join RTE that is specified in the query. Therefore, this
+ * routine is the only place that should call build_simple_rel with
+ * reloptkind RELOPT_BASEREL. (Note: "other rel" RelOptInfos for the
+ * members of any appendrels we find here are added built later when
+ * query_planner calls add_other_rels_to_query().)
*/
void
add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
@@ -133,6 +136,48 @@ add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
(int) nodeTag(jtnode));
}
+/*
+ * add_other_rels_to_query
+ *
+ * Scan the query's jointree and for each base rels that is an appendrel,
+ * create otherrel RelOptInfos of its children
+ *
+ * At the end of this process, there should be RelOptInfos for all relations
+ * that will be scanned by the query.
+ */
+void
+add_other_rels_to_query(PlannerInfo *root, Node *jtnode)
+{
+ if (jtnode == NULL)
+ return;
+ if (IsA(jtnode, RangeTblRef))
+ {
+ int varno = ((RangeTblRef *) jtnode)->rtindex;
+ RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);
+
+ if (rte->inh)
+ (void) add_appendrel_other_rels(root, rte, varno);
+ }
+ else if (IsA(jtnode, FromExpr))
+ {
+ FromExpr *f = (FromExpr *) jtnode;
+ ListCell *l;
+
+ foreach(l, f->fromlist)
+ add_other_rels_to_query(root, lfirst(l));
+ }
+ else if (IsA(jtnode, JoinExpr))
+ {
+ JoinExpr *j = (JoinExpr *) jtnode;
+
+ add_other_rels_to_query(root, j->larg);
+ add_other_rels_to_query(root, j->rarg);
+ }
+ else
+ elog(ERROR, "unrecognized node type: %d",
+ (int) nodeTag(jtnode));
+}
+
/*****************************************************************************
*
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index 3cedd01c98..03c81772a3 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -159,10 +159,8 @@ query_planner(PlannerInfo *root, List *tlist,
setup_append_rel_array(root);
/*
- * Construct RelOptInfo nodes for all base relations in query, and
- * indirectly for all appendrel member relations ("other rels"). This
- * will give us a RelOptInfo for every "simple" (non-join) rel involved in
- * the query.
+ * Construct RelOptInfo nodes for all base relations directly mentioned
+ * in query, but not any appendrel member relations ("other rels") yet.
*
* Note: the reason we find the rels by searching the jointree and
* appendrel list, rather than just scanning the rangetable, is that the
@@ -204,6 +202,15 @@ query_planner(PlannerInfo *root, List *tlist,
generate_base_implied_equalities(root);
/*
+ * Now that we have restrict clauses figured out and assigned to proper
+ * base rels, we can proceed to add otherrels, that is, UNION ALL child
+ * tables, inheritance child tables. Having restrict clauses ready helps
+ * to exclude any children that wouldn't be necessary to scan, based on
+ * constraint exclusion and partition pruning.
+ */
+ add_other_rels_to_query(root, (Node *) root->parse->jointree);
+
+ /*
* We have completed merging equivalence sets, so it's now possible to
* generate pathkeys in canonical form; so compute query_pathkeys and
* other pathkeys fields in PlannerInfo.
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 4130514952..a6c3eedc56 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -16,19 +16,26 @@
#include <limits.h>
+#include "access/table.h"
#include "miscadmin.h"
+#include "nodes/makefuncs.h"
#include "optimizer/appendinfo.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
+#include "optimizer/inherit.h"
+#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/placeholder.h"
#include "optimizer/plancat.h"
+#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
#include "partitioning/partbounds.h"
+#include "partitioning/partdesc.h"
#include "utils/hsearch.h"
+#include "utils/rel.h"
typedef struct JoinHashEntry
@@ -273,53 +280,80 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
root->qual_security_level = Max(root->qual_security_level,
list_length(rte->securityQuals));
+ return rel;
+}
+
+/*
+ * add_appendrel_other_rels
+ * This adds the "other rel" RelOptInfos a given "appendrel" baserel
+ *
+ * Parent relation in this case is the parent subquery in the flattened UNION
+ * ALL case or an inheritance parent table.
+ */
+void
+add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti)
+{
+ ListCell *l;
+ RelOptInfo *rel;
+ Relation relation = NULL;
+ int i;
+
+ rel = find_base_rel(root, rti);
+
/*
- * If this rel is an appendrel parent, recurse to build "other rel"
- * RelOptInfos for its children. They are "other rels" because they are
- * not in the main join tree, but we will need RelOptInfos to plan access
- * to them.
+ * For partitioned tables, we need to store the child RelOptInfos in the
+ * rel->part_rels array too.
*/
- if (rte->inh)
+ if (rel->part_scheme)
{
- ListCell *l;
- int nparts = rel->nparts;
- int cnt_parts = 0;
-
- if (nparts > 0)
- rel->part_rels = (RelOptInfo **)
- palloc(sizeof(RelOptInfo *) * nparts);
-
- foreach(l, root->append_rel_list)
- {
- AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
- RelOptInfo *childrel;
-
- /* append_rel_list contains all append rels; ignore others */
- if (appinfo->parent_relid != relid)
- continue;
-
- childrel = build_simple_rel(root, appinfo->child_relid,
- rel);
-
- /* Nothing more to do for an unpartitioned table. */
- if (!rel->part_scheme)
- continue;
-
- /*
- * The order of partition OIDs in append_rel_list is the same as
- * the order in the PartitionDesc, so the order of part_rels will
- * also match the PartitionDesc. See expand_partitioned_rtentry.
- */
- Assert(cnt_parts < nparts);
- rel->part_rels[cnt_parts] = childrel;
- cnt_parts++;
- }
-
- /* We should have seen all the child partitions. */
- Assert(cnt_parts == nparts);
+ rel->part_rels = (RelOptInfo **)
+ palloc0(sizeof(RelOptInfo *) * rel->nparts);
+ relation = table_open(rte->relid, NoLock);
}
- return rel;
+ /*
+ * We don't need to use expand_planner_arrays in this case, because
+ * no new child RTEs are created. setup_simple_rel_arrays() and
+ * setup_append_rel_array would've considered these child RTEs when
+ * allocating space for various arrays.
+ */
+ i = 0;
+ foreach(l, root->append_rel_list)
+ {
+ AppendRelInfo *appinfo = lfirst(l);
+ Index childRTindex = appinfo->child_relid;
+ RangeTblEntry *childrte;
+ RelOptInfo *childrel;
+
+ if (appinfo->parent_relid != rti)
+ continue;
+
+ Assert(childRTindex < root->simple_rel_array_size);
+ childrte = root->simple_rte_array[childRTindex];
+ Assert(childrte != NULL);
+ childrel = build_simple_rel(root, childRTindex, rel);
+
+ /*
+ * For partitioned parents, we also need to add childrel to its
+ * part_rels array. The order in which child tables appear in
+ * append_rel_list is same as the order in which they appear in the
+ * parent's PartitionDesc, so assigning partitions like this works.
+ */
+ if (rel->part_scheme != NULL)
+ {
+ Assert(rel->nparts > 0 && i < rel->nparts);
+ rel->part_rels[i] = childrel;
+ }
+
+ i++;
+
+ /* Child may itself be an inherited relation. */
+ if (childrte->inh)
+ add_appendrel_other_rels(root, childrte, childRTindex);
+ }
+
+ if (relation)
+ table_close(relation, NoLock);
}
/*
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 574bb85b50..1a07963a7d 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -279,6 +279,8 @@ extern void setup_simple_rel_arrays(PlannerInfo *root);
extern void setup_append_rel_array(PlannerInfo *root);
extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
RelOptInfo *parent);
+extern void add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte,
+ Index rti);
extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid);
extern RelOptInfo *find_join_rel(PlannerInfo *root, Relids relids);
extern RelOptInfo *build_join_rel(PlannerInfo *root,
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 3bbdb5e2f7..035caac500 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -65,6 +65,7 @@ extern int from_collapse_limit;
extern int join_collapse_limit;
extern void add_base_rels_to_query(PlannerInfo *root, Node *jtnode);
+extern void add_other_rels_to_query(PlannerInfo *root, Node *jtnode);
extern void build_base_rel_tlists(PlannerInfo *root, List *final_tlist);
extern void add_vars_to_targetlist(PlannerInfo *root, List *vars,
Relids where_needed, bool create_new_ph);
--
2.11.0