diff options
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 43 | ||||
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 238 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 31 | ||||
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 26 |
5 files changed, 137 insertions, 207 deletions
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index b718f8fea18..0f26dc78722 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -42,7 +42,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.61 2000/05/31 00:28:22 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.62 2000/06/18 22:44:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -55,10 +55,15 @@ #include "miscadmin.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" -#include "optimizer/internal.h" #include "utils/lsyscache.h" +/* + * The length of a variable-length field in bytes (stupid estimate...) + */ +#define _DEFAULT_ATTRIBUTE_WIDTH_ 12 + + #define LOG2(x) (log(x) / 0.693147180559945) #define LOG6(x) (log(x) / 1.79175946922805) @@ -114,29 +119,17 @@ cost_seqscan(Path *path, RelOptInfo *baserel) if (!enable_seqscan) startup_cost += disable_cost; - /* disk costs */ - if (lfirsti(baserel->relids) < 0) - { - - /* - * cost of sequentially scanning a materialized temporary relation - */ - run_cost += _NONAME_SCAN_COST_; - } - else - { - - /* - * The cost of reading a page sequentially is 1.0, by definition. - * Note that the Unix kernel will typically do some amount of - * read-ahead optimization, so that this cost is less than the - * true cost of reading a page from disk. We ignore that issue - * here, but must take it into account when estimating the cost of - * non-sequential accesses! - */ - run_cost += baserel->pages; /* sequential fetches with cost - * 1.0 */ - } + /* + * disk costs + * + * The cost of reading a page sequentially is 1.0, by definition. + * Note that the Unix kernel will typically do some amount of + * read-ahead optimization, so that this cost is less than the + * true cost of reading a page from disk. We ignore that issue + * here, but must take it into account when estimating the cost of + * non-sequential accesses! + */ + run_cost += baserel->pages; /* sequential fetches with cost 1.0 */ /* CPU costs */ cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost; diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 015b6b2b10a..4915133d0a6 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.92 2000/06/15 03:32:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.93 2000/06/18 22:44:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,7 +23,6 @@ #include "nodes/nodeFuncs.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" -#include "optimizer/internal.h" #include "optimizer/paths.h" #include "optimizer/planmain.h" #include "optimizer/restrictinfo.h" @@ -34,7 +33,6 @@ static List *switch_outer(List *clauses); -static int set_tlist_sort_info(List *tlist, List *pathkeys); static Scan *create_scan_node(Query *root, Path *best_path, List *tlist); static Join *create_join_node(Query *root, JoinPath *best_path, List *tlist); static SeqScan *create_seqscan_node(Path *best_path, List *tlist, @@ -71,8 +69,6 @@ static HashJoin *make_hashjoin(List *tlist, List *qpqual, static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree); static MergeJoin *make_mergejoin(List *tlist, List *qpqual, List *mergeclauses, Plan *righttree, Plan *lefttree); -static Material *make_material(List *tlist, Oid nonameid, Plan *lefttree, - int keycount); static void copy_path_costsize(Plan *dest, Path *src); static void copy_plan_costsize(Plan *dest, Plan *src); static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); @@ -560,10 +556,12 @@ create_nestloop_node(NestPath *best_path, } else if (IsA(inner_node, TidScan)) { - List *inner_tideval = ((TidScan *) inner_node)->tideval; TidScan *innerscan = (TidScan *) inner_node; - ((TidScan *) inner_node)->tideval = join_references(inner_tideval, outer_tlist, inner_tlist, innerscan->scan.scanrelid); + innerscan->tideval = join_references(innerscan->tideval, + outer_tlist, + inner_tlist, + innerscan->scan.scanrelid); } else if (IsA_Join(inner_node)) { @@ -575,9 +573,8 @@ create_nestloop_node(NestPath *best_path, * join --- how can we estimate whether this is a good thing to * do? */ - inner_node = (Plan *) make_noname(inner_tlist, - NIL, - inner_node); + inner_node = (Plan *) make_material(inner_tlist, + inner_node); } join_node = make_nestloop(tlist, @@ -632,14 +629,16 @@ create_mergejoin_node(MergePath *best_path, * necessary. The sort cost was already accounted for in the path. */ if (best_path->outersortkeys) - outer_node = (Plan *) make_noname(outer_tlist, - best_path->outersortkeys, - outer_node); + outer_node = (Plan *) + make_sort_from_pathkeys(outer_tlist, + outer_node, + best_path->outersortkeys); if (best_path->innersortkeys) - inner_node = (Plan *) make_noname(inner_tlist, - best_path->innersortkeys, - inner_node); + inner_node = (Plan *) + make_sort_from_pathkeys(inner_tlist, + inner_node, + best_path->innersortkeys); join_node = make_mergejoin(tlist, qpqual, @@ -959,72 +958,6 @@ switch_outer(List *clauses) } /* - * set_tlist_sort_info - * Sets the reskey and reskeyop fields of resdom nodes in a target list - * for a sort node. - * - * 'tlist' is the target list (which is modified in-place). - * tlist's reskey fields must be clear to start with. - * 'pathkeys' is the desired pathkeys for the sort. NIL means no sort. - * - * Returns the number of sort keys assigned (which might be less than - * length(pathkeys)!) - */ -static int -set_tlist_sort_info(List *tlist, List *pathkeys) -{ - int keysassigned = 0; - List *i; - - foreach(i, pathkeys) - { - List *keysublist = (List *) lfirst(i); - PathKeyItem *pathkey = NULL; - Resdom *resdom = NULL; - List *j; - - /* - * We can sort by any one of the sort key items listed in this - * sublist. For now, we take the first one that corresponds to an - * available Var in the tlist. - * - * XXX if we have a choice, is there any way of figuring out which - * might be cheapest to execute? (For example, int4lt is likely - * much cheaper to execute than numericlt, but both might appear - * in the same pathkey sublist...) Not clear that we ever will - * have a choice in practice, so it may not matter. - */ - foreach(j, keysublist) - { - pathkey = lfirst(j); - Assert(IsA(pathkey, PathKeyItem)); - resdom = tlist_member(pathkey->key, tlist); - if (resdom) - break; - } - if (!resdom) - elog(ERROR, "set_tlist_sort_info: cannot find tlist item to sort"); - - /* - * The resdom might be already marked as a sort key, if the - * pathkeys contain duplicate entries. (This can happen in - * scenarios where multiple mergejoinable clauses mention the same - * var, for example.) In that case the current pathkey is - * essentially a no-op, because only one value can be seen within - * any subgroup where it would be consulted. We can ignore it. - */ - if (resdom->reskey == 0) - { - /* OK, mark it as a sort key and set the sort operator regproc */ - resdom->reskey = ++keysassigned; - resdom->reskeyop = get_opcode(pathkey->sortop); - } - } - - return keysassigned; -} - -/* * Copy cost and size info from a Path node to the Plan node created from it. * The executor won't use this info, but it's needed by EXPLAIN. */ @@ -1078,50 +1011,7 @@ copy_plan_costsize(Plan *dest, Plan *src) * *****************************************************************************/ -/* - * make_noname - * Create plan node to sort or materialize relations into noname. - * - * 'tlist' is the target list of the scan to be sorted or materialized - * 'pathkeys' is the list of pathkeys by which the result is to be sorted - * (NIL implies no sort needed, just materialize it) - * 'subplan' is the node which yields input tuples - */ -Noname * -make_noname(List *tlist, - List *pathkeys, - Plan *subplan) -{ - List *noname_tlist; - int numsortkeys; - Plan *retval; - - /* Create a new target list for the noname, with sort keys set. */ - noname_tlist = new_unsorted_tlist(tlist); - numsortkeys = set_tlist_sort_info(noname_tlist, pathkeys); - - if (numsortkeys > 0) - { - /* need to sort */ - retval = (Plan *) make_sort(noname_tlist, - _NONAME_RELATION_ID_, - subplan, - numsortkeys); - } - else - { - /* no sort */ - retval = (Plan *) make_material(noname_tlist, - _NONAME_RELATION_ID_, - subplan, - 0); - } - - return (Noname *) retval; -} - - -static SeqScan * +static SeqScan * make_seqscan(List *qptlist, List *qpqual, Index scanrelid) @@ -1256,8 +1146,14 @@ make_mergejoin(List *tlist, return node; } +/* + * To use make_sort directly, you must already have marked the tlist + * with reskey and reskeyop information. The keys had better be + * non-redundant, too (ie, there had better be tlist items marked with + * each key number from 1 to keycount), or the executor will get confused! + */ Sort * -make_sort(List *tlist, Oid nonameid, Plan *lefttree, int keycount) +make_sort(List *tlist, Plan *lefttree, int keycount) { Sort *node = makeNode(Sort); Plan *plan = &node->plan; @@ -1272,17 +1168,84 @@ make_sort(List *tlist, Oid nonameid, Plan *lefttree, int keycount) plan->qual = NIL; plan->lefttree = lefttree; plan->righttree = NULL; - node->nonameid = nonameid; node->keycount = keycount; return node; } -static Material * -make_material(List *tlist, - Oid nonameid, - Plan *lefttree, - int keycount) +/* + * make_sort_from_pathkeys + * Create sort plan to sort according to given pathkeys + * + * 'tlist' is the target list of the input plan + * 'lefttree' is the node which yields input tuples + * 'pathkeys' is the list of pathkeys by which the result is to be sorted + * + * We must convert the pathkey information into reskey and reskeyop fields + * of resdom nodes in the sort plan's target list. + */ +Sort * +make_sort_from_pathkeys(List *tlist, Plan *lefttree, List *pathkeys) +{ + List *sort_tlist; + List *i; + int numsortkeys = 0; + + /* Create a new target list for the sort, with sort keys set. */ + sort_tlist = new_unsorted_tlist(tlist); + + foreach(i, pathkeys) + { + List *keysublist = (List *) lfirst(i); + PathKeyItem *pathkey = NULL; + Resdom *resdom = NULL; + List *j; + + /* + * We can sort by any one of the sort key items listed in this + * sublist. For now, we take the first one that corresponds to an + * available Var in the sort_tlist. + * + * XXX if we have a choice, is there any way of figuring out which + * might be cheapest to execute? (For example, int4lt is likely + * much cheaper to execute than numericlt, but both might appear + * in the same pathkey sublist...) Not clear that we ever will + * have a choice in practice, so it may not matter. + */ + foreach(j, keysublist) + { + pathkey = lfirst(j); + Assert(IsA(pathkey, PathKeyItem)); + resdom = tlist_member(pathkey->key, sort_tlist); + if (resdom) + break; + } + if (!resdom) + elog(ERROR, "make_sort_from_pathkeys: cannot find tlist item to sort"); + + /* + * The resdom might be already marked as a sort key, if the + * pathkeys contain duplicate entries. (This can happen in + * scenarios where multiple mergejoinable clauses mention the same + * var, for example.) In that case the current pathkey is + * essentially a no-op, because only one value can be seen within + * any subgroup where it would be consulted. We can ignore it. + */ + if (resdom->reskey == 0) + { + /* OK, mark it as a sort key and set the sort operator regproc */ + resdom->reskey = ++numsortkeys; + resdom->reskeyop = get_opcode(pathkey->sortop); + } + } + + Assert(numsortkeys > 0); + + return make_sort(sort_tlist, lefttree, numsortkeys); +} + +Material * +make_material(List *tlist, Plan *lefttree) { Material *node = makeNode(Material); Plan *plan = &node->plan; @@ -1291,8 +1254,9 @@ make_material(List *tlist, /* * For plausibility, make startup & total costs equal total cost of - * input plan; this only affects EXPLAIN display not decisions. XXX - * shouldn't we charge some additional cost for materialization? + * input plan; this only affects EXPLAIN display not decisions. + * + * XXX shouldn't we charge some additional cost for materialization? */ plan->startup_cost = plan->total_cost; plan->state = (EState *) NULL; @@ -1300,8 +1264,6 @@ make_material(List *tlist, plan->qual = NIL; plan->lefttree = lefttree; plan->righttree = NULL; - node->nonameid = nonameid; - node->keycount = keycount; return node; } @@ -1420,8 +1382,6 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList) plan->qual = NIL; plan->lefttree = lefttree; plan->righttree = NULL; - node->nonameid = _NONAME_RELATION_ID_; - node->keycount = 0; /* * convert SortClause list into array of attr indexes, as wanted by diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index fdb7be92447..49d400dee9d 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.83 2000/06/15 03:32:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.84 2000/06/18 22:44:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,7 +21,6 @@ #include "executor/executor.h" #include "nodes/makefuncs.h" #include "optimizer/clauses.h" -#include "optimizer/internal.h" #include "optimizer/paths.h" #include "optimizer/plancat.h" #include "optimizer/planmain.h" @@ -40,7 +39,7 @@ static List *make_subplanTargetList(Query *parse, List *tlist, static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup, List *groupClause, AttrNumber *grpColIdx, bool is_presorted, Plan *subplan); -static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode); +static Plan *make_sortplan(List *tlist, Plan *plannode, List *sortcls); /***************************************************************************** * @@ -641,7 +640,8 @@ union_planner(Query *parse, if (parse->sortClause) { if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys)) - result_plan = make_sortplan(tlist, parse->sortClause, result_plan); + result_plan = make_sortplan(tlist, result_plan, + parse->sortClause); } /* @@ -818,10 +818,9 @@ make_groupplan(List *group_tlist, } } - subplan = (Plan *) make_sort(sort_tlist, - _NONAME_RELATION_ID_, - subplan, - keyno); + Assert(keyno > 0); + + subplan = (Plan *) make_sort(sort_tlist, subplan, keyno); } return (Plan *) make_group(group_tlist, tuplePerGroup, numCols, @@ -833,9 +832,9 @@ make_groupplan(List *group_tlist, * Add a Sort node to implement an explicit ORDER BY clause. */ static Plan * -make_sortplan(List *tlist, List *sortcls, Plan *plannode) +make_sortplan(List *tlist, Plan *plannode, List *sortcls) { - List *temp_tlist; + List *sort_tlist; List *i; int keyno = 0; @@ -843,13 +842,12 @@ make_sortplan(List *tlist, List *sortcls, Plan *plannode) * First make a copy of the tlist so that we don't corrupt the * original. */ - - temp_tlist = new_unsorted_tlist(tlist); + sort_tlist = new_unsorted_tlist(tlist); foreach(i, sortcls) { SortClause *sortcl = (SortClause *) lfirst(i); - TargetEntry *tle = get_sortgroupclause_tle(sortcl, temp_tlist); + TargetEntry *tle = get_sortgroupclause_tle(sortcl, sort_tlist); Resdom *resdom = tle->resdom; /* @@ -865,10 +863,9 @@ make_sortplan(List *tlist, List *sortcls, Plan *plannode) } } - return (Plan *) make_sort(temp_tlist, - _NONAME_RELATION_ID_, - plannode, - keyno); + Assert(keyno > 0); + + return (Plan *) make_sort(sort_tlist, plannode, keyno); } /* diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 87e508ef8f7..cd624fb111d 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.37 2000/05/30 00:49:47 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.38 2000/06/18 22:44:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -363,9 +363,7 @@ make_subplan(SubLink *slink) } if (use_material) { - plan = (Plan *) make_noname(plan->targetlist, - NIL, - plan); + plan = (Plan *) make_material(plan->targetlist, plan); node->plan = plan; } } diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index da7059ce915..070fabf7669 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -8,14 +8,13 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.26 2000/04/12 17:15:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.27 2000/06/18 22:44:12 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "optimizer/cost.h" -#include "optimizer/internal.h" #include "optimizer/joininfo.h" #include "optimizer/pathnode.h" #include "optimizer/plancat.h" @@ -76,26 +75,9 @@ get_base_rel(Query *root, int relid) rel->joininfo = NIL; rel->innerjoin = NIL; - if (relid < 0) - { - - /* - * If the relation is a materialized relation, assume constants - * for sizes. - */ - rel->pages = _NONAME_RELATION_PAGES_; - rel->tuples = _NONAME_RELATION_TUPLES_; - } - else - { - - /* - * Otherwise, retrieve relation statistics from the system - * catalogs. - */ - relation_info(root, relid, - &rel->indexed, &rel->pages, &rel->tuples); - } + /* Retrieve relation statistics from the system catalogs. */ + relation_info(root, relid, + &rel->indexed, &rel->pages, &rel->tuples); root->base_rel_list = lcons(rel, root->base_rel_list); |