1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-15 19:21:59 +03:00

New cost model for planning, incorporating a penalty for random page

accesses versus sequential accesses, a (very crude) estimate of the
effects of caching on random page accesses, and cost to evaluate WHERE-
clause expressions.  Export critical parameters for this model as SET
variables.  Also, create SET variables for the planner's enable flags
(enable_seqscan, enable_indexscan, etc) so that these can be controlled
more conveniently than via PGOPTIONS.

Planner now estimates both startup cost (cost before retrieving
first tuple) and total cost of each path, so it can optimize queries
with LIMIT on a reasonable basis by interpolating between these costs.
Same facility is a win for EXISTS(...) subqueries and some other cases.

Redesign pathkey representation to achieve a major speedup in planning
(I saw as much as 5X on a 10-way join); also minor changes in planner
to reduce memory consumption by recycling discarded Path nodes and
not constructing unnecessary lists.

Minor cleanups to display more-plausible costs in some cases in
EXPLAIN output.

Initdb forced by change in interface to index cost estimation
functions.
This commit is contained in:
Tom Lane
2000-02-15 20:49:31 +00:00
parent 553b5da6a1
commit b1577a7c78
50 changed files with 3200 additions and 1723 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.44 2000/02/15 03:37:26 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.45 2000/02/15 20:49:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -122,28 +122,35 @@ plan_union_queries(Query *parse)
/* Is this a simple one */
if (!union_all_found ||
!union_found ||
/* A trailing UNION negates the affect of earlier UNION ALLs */
/* A trailing UNION negates the effect of earlier UNION ALLs */
!last_union_all_flag)
{
List *hold_unionClause = parse->unionClause;
double tuple_fraction = -1.0; /* default processing */
/* we will do this later, so don't do it now */
/* we will do sorting later, so don't do it now */
if (!union_all_found ||
!last_union_all_flag)
{
parse->sortClause = NIL;
parse->distinctClause = NIL;
/*
* force lower-level planning to assume that all tuples will
* be retrieved, even if it sees a LIMIT in the query node.
*/
tuple_fraction = 0.0;
}
parse->unionClause = NIL; /* prevent recursion */
union_plans = lcons(union_planner(parse), NIL);
union_plans = lcons(union_planner(parse, tuple_fraction), NIL);
union_rts = lcons(parse->rtable, NIL);
foreach(ulist, hold_unionClause)
{
Query *union_query = lfirst(ulist);
union_plans = lappend(union_plans, union_planner(union_query));
union_plans = lappend(union_plans,
union_planner(union_query, tuple_fraction));
union_rts = lappend(union_rts, union_query->rtable);
}
}
@ -165,9 +172,12 @@ plan_union_queries(Query *parse)
/*
* Recursion, but UNION only. The last one is a UNION, so it will
* not come here in recursion,
* not come here in recursion.
*
* XXX is it OK to pass default -1 to union_planner in this path,
* or should we force a tuple_fraction value?
*/
union_plans = lcons(union_planner(parse), NIL);
union_plans = lcons(union_planner(parse, -1.0), NIL);
union_rts = lcons(parse->rtable, NIL);
/* Append the remaining UNION ALLs */
@ -175,7 +185,8 @@ plan_union_queries(Query *parse)
{
Query *union_all_query = lfirst(ulist);
union_plans = lappend(union_plans, union_planner(union_all_query));
union_plans = lappend(union_plans,
union_planner(union_all_query, -1.0));
union_rts = lappend(union_rts, union_all_query->rtable);
}
}
@ -295,6 +306,7 @@ plan_inherit_query(Relids relids,
List *union_plans = NIL;
List *union_rtentries = NIL;
List *save_tlist = root->targetList;
double tuple_fraction;
List *i;
/*
@ -303,6 +315,17 @@ plan_inherit_query(Relids relids,
*/
root->targetList = NIL;
/*
* If we are going to need sorting or grouping at the top level,
* force lower-level planners to assume that all tuples will be
* retrieved.
*/
if (root->distinctClause || root->sortClause ||
root->groupClause || root->hasAggs)
tuple_fraction = 0.0; /* will need all tuples from each subplan */
else
tuple_fraction = -1.0; /* default behavior is OK (I think) */
foreach(i, relids)
{
int relid = lfirsti(i);
@ -344,7 +367,8 @@ plan_inherit_query(Relids relids,
relid,
new_root);
union_plans = lappend(union_plans, union_planner(new_root));
union_plans = lappend(union_plans,
union_planner(new_root, tuple_fraction));
union_rtentries = lappend(union_rtentries, new_rt_entry);
}
@ -551,14 +575,17 @@ make_append(List *appendplans,
node->unionrtables = unionrtables;
node->inheritrelid = rt_index;
node->inheritrtable = inheritrtable;
node->plan.cost = 0;
node->plan.startup_cost = 0;
node->plan.total_cost = 0;
node->plan.plan_rows = 0;
node->plan.plan_width = 0;
foreach(subnode, appendplans)
{
Plan *subplan = (Plan *) lfirst(subnode);
node->plan.cost += subplan->cost;
if (subnode == appendplans) /* first node? */
node->plan.startup_cost = subplan->startup_cost;
node->plan.total_cost += subplan->total_cost;
node->plan.plan_rows += subplan->plan_rows;
if (node->plan.plan_width < subplan->plan_width)
node->plan.plan_width = subplan->plan_width;