diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 0d87291025f5e08f7b9c447cb8db8033c74e221c..07a99e9c6b7c6503542e1346cce33ef2377aefa9 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.162 2007/04/21 06:18:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.163 2007/04/21 21:01:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,7 +39,8 @@ int geqo_threshold; static void set_base_rel_pathlists(PlannerInfo *root); -static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti); +static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte); static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, @@ -144,7 +145,7 @@ set_base_rel_pathlists(PlannerInfo *root) if (rel->reloptkind != RELOPT_BASEREL) continue; - set_rel_pathlist(root, rel, rti); + set_rel_pathlist(root, rel, rti, root->simple_rte_array[rti]); } } @@ -153,10 +154,9 @@ set_base_rel_pathlists(PlannerInfo *root) * Build access paths for a base relation */ static void -set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti) +set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte) { - RangeTblEntry *rte = rt_fetch(rti, root->parse->rtable); - if (rte->inh) { /* It's an "append relation", process accordingly */ @@ -200,8 +200,11 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) * If we can prove we don't need to scan the rel via constraint exclusion, * set up a single dummy path for it. (Rather than inventing a special * "dummy" path type, we represent this as an AppendPath with no members.) + * We only need to check for regular baserels; if it's an otherrel, CE + * was already checked in set_append_rel_pathlist(). */ - if (relation_excluded_by_constraints(rel, rte)) + if (rel->reloptkind == RELOPT_BASEREL && + relation_excluded_by_constraints(rel, rte)) { /* Set dummy size estimates --- we leave attr_widths[] as zeroes */ rel->rows = 0; @@ -294,6 +297,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, { AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); int childRTindex; + RangeTblEntry *childRTE; RelOptInfo *childrel; Path *childpath; ListCell *parentvars; @@ -304,6 +308,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, continue; childRTindex = appinfo->child_relid; + childRTE = root->simple_rte_array[childRTindex]; /* * The child rel's RelOptInfo was already created during @@ -313,18 +318,29 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL); /* - * Copy the parent's targetlist and quals to the child, with - * appropriate substitution of variables. + * We have to copy the parent's targetlist and quals to the child, + * with appropriate substitution of variables. However, only the + * baserestrictinfo quals are needed before we can check for + * constraint exclusion; so do that first and then check to see + * if we can disregard this child. */ - childrel->reltargetlist = (List *) - adjust_appendrel_attrs((Node *) rel->reltargetlist, - appinfo); childrel->baserestrictinfo = (List *) adjust_appendrel_attrs((Node *) rel->baserestrictinfo, appinfo); + + if (relation_excluded_by_constraints(childrel, childRTE)) + { + /* this child need not be scanned, so just disregard it */ + continue; + } + + /* CE failed, so finish copying targetlist and join quals */ childrel->joininfo = (List *) adjust_appendrel_attrs((Node *) rel->joininfo, appinfo); + childrel->reltargetlist = (List *) + adjust_appendrel_attrs((Node *) rel->reltargetlist, + appinfo); /* * We have to make child entries in the EquivalenceClass data @@ -353,12 +369,9 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, * It's possible that the child is itself an appendrel, in which case * we can "cut out the middleman" and just add its child paths to our * own list. (We don't try to do this earlier because we need to - * apply both levels of transformation to the quals.) This test also - * handles the case where the child rel need not be scanned because of - * constraint exclusion: it'll have an Append path with no subpaths, - * and will vanish from our list. + * apply both levels of transformation to the quals.) */ - set_rel_pathlist(root, childrel, childRTindex); + set_rel_pathlist(root, childrel, childRTindex, childRTE); childpath = childrel->cheapest_total_path; if (IsA(childpath, AppendPath)) diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index 405ab6fcc3a6275dc1a132e547693b6ce6bbde07..b8bbc29c505bb3c418144644d8d0cac819003d59 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.84 2007/02/19 07:03:28 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.85 2007/04/21 21:01:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -500,7 +500,7 @@ clause_selectivity(PlannerInfo *root, if (var->varlevelsup == 0 && (varRelid == 0 || varRelid == (int) var->varno)) { - RangeTblEntry *rte = rt_fetch(var->varno, root->parse->rtable); + RangeTblEntry *rte = planner_rt_fetch(var->varno, root); if (rte->rtekind == RTE_SUBQUERY) { diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 42a5520b974ebf0f0947923534e349f00be16d69..9cd3a51d8976c99b9157d21341df745f1145fa4a 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -54,7 +54,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.180 2007/04/21 02:41:13 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.181 2007/04/21 21:01:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -856,7 +856,7 @@ cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel) /* Should only be applied to base relations that are functions */ Assert(baserel->relid > 0); - rte = rt_fetch(baserel->relid, root->parse->rtable); + rte = planner_rt_fetch(baserel->relid, root); Assert(rte->rtekind == RTE_FUNCTION); /* Estimate costs of executing the function expression */ @@ -2297,7 +2297,7 @@ set_function_size_estimates(PlannerInfo *root, RelOptInfo *rel) /* Should only be applied to base relations that are functions */ Assert(rel->relid > 0); - rte = rt_fetch(rel->relid, root->parse->rtable); + rte = planner_rt_fetch(rel->relid, root); Assert(rte->rtekind == RTE_FUNCTION); /* Estimate number of rows the function itself will return */ @@ -2323,7 +2323,7 @@ set_values_size_estimates(PlannerInfo *root, RelOptInfo *rel) /* Should only be applied to base relations that are values lists */ Assert(rel->relid > 0); - rte = rt_fetch(rel->relid, root->parse->rtable); + rte = planner_rt_fetch(rel->relid, root); Assert(rte->rtekind == RTE_VALUES); /* diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 9b9645faf28a0d46e9b560e6dce8757f3556ff80..74b89125665f65c66094e71bfb87d7f80399ad5e 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.228 2007/04/06 22:33:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.229 2007/04/21 21:01:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1353,7 +1353,7 @@ create_functionscan_plan(PlannerInfo *root, Path *best_path, /* it should be a function base rel... */ Assert(scan_relid > 0); - rte = rt_fetch(scan_relid, root->parse->rtable); + rte = planner_rt_fetch(scan_relid, root); Assert(rte->rtekind == RTE_FUNCTION); /* Sort clauses into best execution order */ @@ -1388,7 +1388,7 @@ create_valuesscan_plan(PlannerInfo *root, Path *best_path, /* it should be a values base rel... */ Assert(scan_relid > 0); - rte = rt_fetch(scan_relid, root->parse->rtable); + rte = planner_rt_fetch(scan_relid, root); Assert(rte->rtekind == RTE_VALUES); /* Sort clauses into best execution order */ diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index 95f0e64cc4190e7aa680de1b3740d1eeed287398..92ade2fccf56a08831d0be2bc50e3464c98a174d 100644 --- a/src/backend/optimizer/plan/planagg.c +++ b/src/backend/optimizer/plan/planagg.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.30 2007/03/17 00:11:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.31 2007/04/21 21:01:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -116,7 +116,7 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path) if (!IsA(jtnode, RangeTblRef)) return NULL; rtr = (RangeTblRef *) jtnode; - rte = rt_fetch(rtr->rtindex, parse->rtable); + rte = planner_rt_fetch(rtr->rtindex, root); if (rte->rtekind != RTE_RELATION || rte->inh) return NULL; rel = find_base_rel(root, rtr->rtindex); diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index de3944b6b07a757f7a59e201e7d20fe12f71a620..f12e388d7235881c96a7cda4995300f8763d26f4 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.99 2007/01/20 20:45:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.100 2007/04/21 21:01:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -86,6 +86,7 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, Path *cheapestpath; Path *sortedpath; Index rti; + ListCell *lc; double total_pages; /* Make tuple_fraction accessible to lower-level routines */ @@ -123,6 +124,20 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, root->full_join_clauses = NIL; root->oj_info_list = NIL; + /* + * Make a flattened version of the rangetable for faster access (this + * is OK because the rangetable won't change any more). + */ + root->simple_rte_array = (RangeTblEntry **) + palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *)); + rti = 1; + foreach(lc, parse->rtable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); + + root->simple_rte_array[rti++] = rte; + } + /* * Construct RelOptInfo nodes for all base relations in query, and * indirectly for all appendrel member relations ("other rels"). This diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 81f7c99e96310a6584b7999bed6f5656d5b469c9..6d440001d6b2a28a0f6080cbe6805c9c91d8e66c 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.138 2007/02/06 02:59:12 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.139 2007/04/21 21:01:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -800,7 +800,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath) */ if (sub_targetlist && rel->rtekind == RTE_SUBQUERY) { - RangeTblEntry *rte = rt_fetch(rel->relid, root->parse->rtable); + RangeTblEntry *rte = planner_rt_fetch(rel->relid, root); List *sub_tlist_colnos; sub_tlist_colnos = translate_sub_tlist(sub_targetlist, rel->relid); diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 33b081ffffddb93b36f20def780ddaa3fb036819..662fcbaaf8ed6c448c639ea930a2fb70b5aad63d 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.133 2007/04/06 22:33:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.134 2007/04/21 21:01:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -497,6 +497,9 @@ get_relation_constraints(Oid relationObjectId, RelOptInfo *rel) * Detect whether the relation need not be scanned because it has either * self-inconsistent restrictions, or restrictions inconsistent with the * relation's CHECK constraints. + * + * Note: this examines only rel->relid and rel->baserestrictinfo; therefore + * it can be called before filling in other fields of the RelOptInfo. */ bool relation_excluded_by_constraints(RelOptInfo *rel, RangeTblEntry *rte) @@ -595,7 +598,7 @@ build_physical_tlist(PlannerInfo *root, RelOptInfo *rel) { List *tlist = NIL; Index varno = rel->relid; - RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable); + RangeTblEntry *rte = planner_rt_fetch(varno, root); Relation relation; Query *subquery; Var *var; diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 6dfd2f61149e71c2ef87ec965b64a1b850e04aea..56f8f3493c223e539adc91e2d4cd55164204ca4c 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.86 2007/02/22 22:00:25 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.87 2007/04/21 21:01:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -56,15 +56,15 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) RelOptInfo *rel; RangeTblEntry *rte; - /* Fetch RTE for relation */ - Assert(relid > 0 && relid <= list_length(root->parse->rtable)); - rte = rt_fetch(relid, root->parse->rtable); - /* Rel should not exist already */ - Assert(relid < root->simple_rel_array_size); + Assert(relid > 0 && relid < root->simple_rel_array_size); if (root->simple_rel_array[relid] != NULL) elog(ERROR, "rel %d already exists", relid); + /* Fetch RTE for relation */ + rte = root->simple_rte_array[relid]; + Assert(rte != NULL); + rel = makeNode(RelOptInfo); rel->reloptkind = reloptkind; rel->relids = bms_make_singleton(relid); diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 28e95a74eedc0e7534fee3c695a9e5983385bd17..079f5e2cc9dfff4b12ea1c9b7e3fd5183d00bf58 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.232 2007/04/06 22:33:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.233 2007/04/21 21:01:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3487,7 +3487,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid, vardata->atttype = var->vartype; vardata->atttypmod = var->vartypmod; - rte = rt_fetch(var->varno, root->parse->rtable); + rte = root->simple_rte_array[var->varno]; if (rte->inh) { diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 2c26d121ef406abeb50a16a90ffdd7e054f06cef..57af937830f0722a7d393b96fe716edc1d1443c0 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.140 2007/04/06 22:33:43 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.141 2007/04/21 21:01:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -108,6 +108,14 @@ typedef struct PlannerInfo struct RelOptInfo **simple_rel_array; /* All 1-rel RelOptInfos */ int simple_rel_array_size; /* allocated size of array */ + /* + * simple_rte_array is the same length as simple_rel_array and holds + * pointers to the associated rangetable entries. This lets us avoid + * rt_fetch(), which can be a bit slow once large inheritance sets have + * been expanded. + */ + RangeTblEntry **simple_rte_array; /* rangetable as an array */ + /* * join_rel_list is a list of all join-relation RelOptInfos we have * considered in this planning run. For small problems we just scan the @@ -167,6 +175,16 @@ typedef struct PlannerInfo } PlannerInfo; +/* + * In places where it's known that simple_rte_array[] must have been prepared + * already, we just index into it to fetch RTEs. In code that might be + * executed before or after entering query_planner(), use this macro. + */ +#define planner_rt_fetch(rti, root) \ + ((root)->simple_rte_array ? (root)->simple_rte_array[rti] : \ + rt_fetch(rti, (root)->parse->rtable)) + + /*---------- * RelOptInfo * Per-relation information for planning/optimization