Revise cost_qual_eval() to compute both startup (one-time) and per-tuple
costs for expression evaluation, not only per-tuple cost as before. This extension is needed in order to deal realistically with hashed or materialized sub-selects.
This commit is contained in:
parent
d51260aa9d
commit
d4ce5a4f4c
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/Attic/indexcost.sgml,v 2.12 2002/08/22 00:01:40 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/Attic/indexcost.sgml,v 2.13 2003/01/12 22:35:29 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="indexcost">
|
<chapter id="indexcost">
|
||||||
@ -237,9 +237,10 @@ amcostestimate (Query *root,
|
|||||||
* Also, we charge for evaluation of the indexquals at each index tuple.
|
* Also, we charge for evaluation of the indexquals at each index tuple.
|
||||||
* All the costs are assumed to be paid incrementally during the scan.
|
* All the costs are assumed to be paid incrementally during the scan.
|
||||||
*/
|
*/
|
||||||
*indexStartupCost = 0;
|
cost_qual_eval(&index_qual_cost, indexQuals);
|
||||||
|
*indexStartupCost = index_qual_cost.startup;
|
||||||
*indexTotalCost = numIndexPages +
|
*indexTotalCost = numIndexPages +
|
||||||
(cpu_index_tuple_cost + cost_qual_eval(indexQuals)) * numIndexTuples;
|
(cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</step>
|
</step>
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.98 2002/12/30 15:21:21 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.99 2003/01/12 22:35:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -87,7 +87,7 @@ bool enable_hashjoin = true;
|
|||||||
|
|
||||||
static Selectivity estimate_hash_bucketsize(Query *root, Var *var,
|
static Selectivity estimate_hash_bucketsize(Query *root, Var *var,
|
||||||
int nbuckets);
|
int nbuckets);
|
||||||
static bool cost_qual_eval_walker(Node *node, Cost *total);
|
static bool cost_qual_eval_walker(Node *node, QualCost *total);
|
||||||
static Selectivity approx_selectivity(Query *root, List *quals);
|
static Selectivity approx_selectivity(Query *root, List *quals);
|
||||||
static void set_rel_width(Query *root, RelOptInfo *rel);
|
static void set_rel_width(Query *root, RelOptInfo *rel);
|
||||||
static double relation_byte_size(double tuples, int width);
|
static double relation_byte_size(double tuples, int width);
|
||||||
@ -131,7 +131,8 @@ cost_seqscan(Path *path, Query *root,
|
|||||||
run_cost += baserel->pages; /* sequential fetches with cost 1.0 */
|
run_cost += baserel->pages; /* sequential fetches with cost 1.0 */
|
||||||
|
|
||||||
/* CPU costs */
|
/* CPU costs */
|
||||||
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost;
|
startup_cost += baserel->baserestrictcost.startup;
|
||||||
|
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
|
||||||
run_cost += cpu_per_tuple * baserel->tuples;
|
run_cost += cpu_per_tuple * baserel->tuples;
|
||||||
|
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
@ -344,17 +345,25 @@ cost_index(Path *path, Query *root,
|
|||||||
*
|
*
|
||||||
* Normally the indexquals will be removed from the list of restriction
|
* Normally the indexquals will be removed from the list of restriction
|
||||||
* clauses that we have to evaluate as qpquals, so we should subtract
|
* clauses that we have to evaluate as qpquals, so we should subtract
|
||||||
* their costs from baserestrictcost. XXX For a lossy index, not all
|
* their costs from baserestrictcost. But if we are doing a join then
|
||||||
* the quals will be removed and so we really shouldn't subtract their
|
* some of the indexquals are join clauses and shouldn't be subtracted.
|
||||||
* costs; but detecting that seems more expensive than it's worth.
|
* Rather than work out exactly how much to subtract, we don't subtract
|
||||||
* Also, if we are doing a join then some of the indexquals are join
|
* anything.
|
||||||
* clauses and shouldn't be subtracted. Rather than work out exactly
|
*
|
||||||
* how much to subtract, we don't subtract anything.
|
* XXX For a lossy index, not all the quals will be removed and so we
|
||||||
|
* really shouldn't subtract their costs; but detecting that seems more
|
||||||
|
* expensive than it's worth.
|
||||||
*/
|
*/
|
||||||
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost;
|
startup_cost += baserel->baserestrictcost.startup;
|
||||||
|
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
|
||||||
|
|
||||||
if (!is_injoin)
|
if (!is_injoin)
|
||||||
cpu_per_tuple -= cost_qual_eval(indexQuals);
|
{
|
||||||
|
QualCost index_qual_cost;
|
||||||
|
|
||||||
|
cost_qual_eval(&index_qual_cost, indexQuals);
|
||||||
|
cpu_per_tuple -= index_qual_cost.per_tuple;
|
||||||
|
}
|
||||||
|
|
||||||
run_cost += cpu_per_tuple * tuples_fetched;
|
run_cost += cpu_per_tuple * tuples_fetched;
|
||||||
|
|
||||||
@ -386,7 +395,8 @@ cost_tidscan(Path *path, Query *root,
|
|||||||
run_cost += random_page_cost * ntuples;
|
run_cost += random_page_cost * ntuples;
|
||||||
|
|
||||||
/* CPU costs */
|
/* CPU costs */
|
||||||
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost;
|
startup_cost += baserel->baserestrictcost.startup;
|
||||||
|
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
|
||||||
run_cost += cpu_per_tuple * ntuples;
|
run_cost += cpu_per_tuple * ntuples;
|
||||||
|
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
@ -416,7 +426,8 @@ cost_functionscan(Path *path, Query *root, RelOptInfo *baserel)
|
|||||||
cpu_per_tuple = cpu_operator_cost;
|
cpu_per_tuple = cpu_operator_cost;
|
||||||
|
|
||||||
/* Add scanning CPU costs */
|
/* Add scanning CPU costs */
|
||||||
cpu_per_tuple += cpu_tuple_cost + baserel->baserestrictcost;
|
startup_cost += baserel->baserestrictcost.startup;
|
||||||
|
cpu_per_tuple += cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
|
||||||
run_cost += cpu_per_tuple * baserel->tuples;
|
run_cost += cpu_per_tuple * baserel->tuples;
|
||||||
|
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
@ -656,6 +667,7 @@ cost_nestloop(Path *path, Query *root,
|
|||||||
Cost startup_cost = 0;
|
Cost startup_cost = 0;
|
||||||
Cost run_cost = 0;
|
Cost run_cost = 0;
|
||||||
Cost cpu_per_tuple;
|
Cost cpu_per_tuple;
|
||||||
|
QualCost restrict_qual_cost;
|
||||||
double ntuples;
|
double ntuples;
|
||||||
|
|
||||||
if (!enable_nestloop)
|
if (!enable_nestloop)
|
||||||
@ -703,7 +715,9 @@ cost_nestloop(Path *path, Query *root,
|
|||||||
ntuples *= outer_path->parent->rows;
|
ntuples *= outer_path->parent->rows;
|
||||||
|
|
||||||
/* CPU costs */
|
/* CPU costs */
|
||||||
cpu_per_tuple = cpu_tuple_cost + cost_qual_eval(restrictlist);
|
cost_qual_eval(&restrict_qual_cost, restrictlist);
|
||||||
|
startup_cost += restrict_qual_cost.startup;
|
||||||
|
cpu_per_tuple = cpu_tuple_cost + restrict_qual_cost.per_tuple;
|
||||||
run_cost += cpu_per_tuple * ntuples;
|
run_cost += cpu_per_tuple * ntuples;
|
||||||
|
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
@ -736,6 +750,7 @@ cost_mergejoin(Path *path, Query *root,
|
|||||||
Cost startup_cost = 0;
|
Cost startup_cost = 0;
|
||||||
Cost run_cost = 0;
|
Cost run_cost = 0;
|
||||||
Cost cpu_per_tuple;
|
Cost cpu_per_tuple;
|
||||||
|
QualCost restrict_qual_cost;
|
||||||
RestrictInfo *firstclause;
|
RestrictInfo *firstclause;
|
||||||
Var *leftvar;
|
Var *leftvar;
|
||||||
double outer_rows,
|
double outer_rows,
|
||||||
@ -850,7 +865,9 @@ cost_mergejoin(Path *path, Query *root,
|
|||||||
outer_path->parent->rows * inner_path->parent->rows;
|
outer_path->parent->rows * inner_path->parent->rows;
|
||||||
|
|
||||||
/* CPU costs */
|
/* CPU costs */
|
||||||
cpu_per_tuple = cpu_tuple_cost + cost_qual_eval(restrictlist);
|
cost_qual_eval(&restrict_qual_cost, restrictlist);
|
||||||
|
startup_cost += restrict_qual_cost.startup;
|
||||||
|
cpu_per_tuple = cpu_tuple_cost + restrict_qual_cost.per_tuple;
|
||||||
run_cost += cpu_per_tuple * ntuples;
|
run_cost += cpu_per_tuple * ntuples;
|
||||||
|
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
@ -878,6 +895,7 @@ cost_hashjoin(Path *path, Query *root,
|
|||||||
Cost startup_cost = 0;
|
Cost startup_cost = 0;
|
||||||
Cost run_cost = 0;
|
Cost run_cost = 0;
|
||||||
Cost cpu_per_tuple;
|
Cost cpu_per_tuple;
|
||||||
|
QualCost restrict_qual_cost;
|
||||||
double ntuples;
|
double ntuples;
|
||||||
double outerbytes = relation_byte_size(outer_path->parent->rows,
|
double outerbytes = relation_byte_size(outer_path->parent->rows,
|
||||||
outer_path->parent->width);
|
outer_path->parent->width);
|
||||||
@ -984,7 +1002,9 @@ cost_hashjoin(Path *path, Query *root,
|
|||||||
outer_path->parent->rows * inner_path->parent->rows;
|
outer_path->parent->rows * inner_path->parent->rows;
|
||||||
|
|
||||||
/* CPU costs */
|
/* CPU costs */
|
||||||
cpu_per_tuple = cpu_tuple_cost + cost_qual_eval(restrictlist);
|
cost_qual_eval(&restrict_qual_cost, restrictlist);
|
||||||
|
startup_cost += restrict_qual_cost.startup;
|
||||||
|
cpu_per_tuple = cpu_tuple_cost + restrict_qual_cost.per_tuple;
|
||||||
run_cost += cpu_per_tuple * ntuples;
|
run_cost += cpu_per_tuple * ntuples;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1185,16 +1205,20 @@ estimate_hash_bucketsize(Query *root, Var *var, int nbuckets)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* cost_qual_eval
|
* cost_qual_eval
|
||||||
* Estimate the CPU cost of evaluating a WHERE clause (once).
|
* Estimate the CPU costs of evaluating a WHERE clause.
|
||||||
* The input can be either an implicitly-ANDed list of boolean
|
* The input can be either an implicitly-ANDed list of boolean
|
||||||
* expressions, or a list of RestrictInfo nodes.
|
* expressions, or a list of RestrictInfo nodes.
|
||||||
|
* The result includes both a one-time (startup) component,
|
||||||
|
* and a per-evaluation component.
|
||||||
*/
|
*/
|
||||||
Cost
|
void
|
||||||
cost_qual_eval(List *quals)
|
cost_qual_eval(QualCost *cost, List *quals)
|
||||||
{
|
{
|
||||||
Cost total = 0;
|
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
|
cost->startup = 0;
|
||||||
|
cost->per_tuple = 0;
|
||||||
|
|
||||||
/* We don't charge any cost for the implicit ANDing at top level ... */
|
/* We don't charge any cost for the implicit ANDing at top level ... */
|
||||||
|
|
||||||
foreach(l, quals)
|
foreach(l, quals)
|
||||||
@ -1205,31 +1229,32 @@ cost_qual_eval(List *quals)
|
|||||||
* RestrictInfo nodes contain an eval_cost field reserved for this
|
* RestrictInfo nodes contain an eval_cost field reserved for this
|
||||||
* routine's use, so that it's not necessary to evaluate the qual
|
* routine's use, so that it's not necessary to evaluate the qual
|
||||||
* clause's cost more than once. If the clause's cost hasn't been
|
* clause's cost more than once. If the clause's cost hasn't been
|
||||||
* computed yet, the field will contain -1.
|
* computed yet, the field's startup value will contain -1.
|
||||||
*/
|
*/
|
||||||
if (qual && IsA(qual, RestrictInfo))
|
if (qual && IsA(qual, RestrictInfo))
|
||||||
{
|
{
|
||||||
RestrictInfo *restrictinfo = (RestrictInfo *) qual;
|
RestrictInfo *restrictinfo = (RestrictInfo *) qual;
|
||||||
|
|
||||||
if (restrictinfo->eval_cost < 0)
|
if (restrictinfo->eval_cost.startup < 0)
|
||||||
{
|
{
|
||||||
restrictinfo->eval_cost = 0;
|
restrictinfo->eval_cost.startup = 0;
|
||||||
|
restrictinfo->eval_cost.per_tuple = 0;
|
||||||
cost_qual_eval_walker((Node *) restrictinfo->clause,
|
cost_qual_eval_walker((Node *) restrictinfo->clause,
|
||||||
&restrictinfo->eval_cost);
|
&restrictinfo->eval_cost);
|
||||||
}
|
}
|
||||||
total += restrictinfo->eval_cost;
|
cost->startup += restrictinfo->eval_cost.startup;
|
||||||
|
cost->per_tuple += restrictinfo->eval_cost.per_tuple;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* If it's a bare expression, must always do it the hard way */
|
/* If it's a bare expression, must always do it the hard way */
|
||||||
cost_qual_eval_walker(qual, &total);
|
cost_qual_eval_walker(qual, cost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return total;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
cost_qual_eval_walker(Node *node, Cost *total)
|
cost_qual_eval_walker(Node *node, QualCost *total)
|
||||||
{
|
{
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return false;
|
return false;
|
||||||
@ -1246,43 +1271,96 @@ cost_qual_eval_walker(Node *node, Cost *total)
|
|||||||
if (IsA(node, FuncExpr) ||
|
if (IsA(node, FuncExpr) ||
|
||||||
IsA(node, OpExpr) ||
|
IsA(node, OpExpr) ||
|
||||||
IsA(node, DistinctExpr))
|
IsA(node, DistinctExpr))
|
||||||
*total += cpu_operator_cost;
|
{
|
||||||
|
total->per_tuple += cpu_operator_cost;
|
||||||
|
}
|
||||||
|
else if (IsA(node, SubLink))
|
||||||
|
{
|
||||||
|
/* This routine should not be applied to un-planned expressions */
|
||||||
|
elog(ERROR, "cost_qual_eval: can't handle unplanned sub-select");
|
||||||
|
}
|
||||||
else if (IsA(node, SubPlan))
|
else if (IsA(node, SubPlan))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* A subplan node in an expression indicates that the
|
* A subplan node in an expression typically indicates that the
|
||||||
* subplan will be executed on each evaluation, so charge
|
* subplan will be executed on each evaluation, so charge accordingly.
|
||||||
* accordingly. (We assume that sub-selects that can be
|
* (Sub-selects that can be executed as InitPlans have already been
|
||||||
* executed as InitPlans have already been removed from
|
* removed from the expression.)
|
||||||
* the expression.)
|
*
|
||||||
|
* An exception occurs when we have decided we can implement the
|
||||||
|
* subplan by hashing.
|
||||||
*
|
*
|
||||||
* NOTE: this logic should agree with the estimates used by
|
|
||||||
* make_subplan() in plan/subselect.c.
|
|
||||||
*/
|
*/
|
||||||
SubPlan *subplan = (SubPlan *) node;
|
SubPlan *subplan = (SubPlan *) node;
|
||||||
Plan *plan = subplan->plan;
|
Plan *plan = subplan->plan;
|
||||||
Cost subcost;
|
|
||||||
|
if (subplan->useHashTable)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If we are using a hash table for the subquery outputs, then
|
||||||
|
* the cost of evaluating the query is a one-time cost.
|
||||||
|
* We charge one cpu_operator_cost per tuple for the work of
|
||||||
|
* loading the hashtable, too.
|
||||||
|
*/
|
||||||
|
total->startup += plan->total_cost +
|
||||||
|
cpu_operator_cost * plan->plan_rows;
|
||||||
|
/*
|
||||||
|
* The per-tuple costs include the cost of evaluating the
|
||||||
|
* lefthand expressions, plus the cost of probing the hashtable.
|
||||||
|
* Recursion into the exprs list will handle the lefthand
|
||||||
|
* expressions properly, and will count one cpu_operator_cost
|
||||||
|
* for each comparison operator. That is probably too low for
|
||||||
|
* the probing cost, but it's hard to make a better estimate,
|
||||||
|
* so live with it for now.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Otherwise we will be rescanning the subplan output on each
|
||||||
|
* evaluation. We need to estimate how much of the output
|
||||||
|
* we will actually need to scan. NOTE: this logic should
|
||||||
|
* agree with the estimates used by make_subplan() in
|
||||||
|
* plan/subselect.c.
|
||||||
|
*/
|
||||||
|
Cost plan_run_cost = plan->total_cost - plan->startup_cost;
|
||||||
|
|
||||||
if (subplan->subLinkType == EXISTS_SUBLINK)
|
if (subplan->subLinkType == EXISTS_SUBLINK)
|
||||||
{
|
{
|
||||||
/* we only need to fetch 1 tuple */
|
/* we only need to fetch 1 tuple */
|
||||||
subcost = plan->startup_cost +
|
total->per_tuple += plan_run_cost / plan->plan_rows;
|
||||||
(plan->total_cost - plan->startup_cost) / plan->plan_rows;
|
|
||||||
}
|
}
|
||||||
else if (subplan->subLinkType == ALL_SUBLINK ||
|
else if (subplan->subLinkType == ALL_SUBLINK ||
|
||||||
subplan->subLinkType == ANY_SUBLINK)
|
subplan->subLinkType == ANY_SUBLINK)
|
||||||
{
|
{
|
||||||
/* assume we need 50% of the tuples */
|
/* assume we need 50% of the tuples */
|
||||||
subcost = plan->startup_cost +
|
total->per_tuple += 0.50 * plan_run_cost;
|
||||||
0.50 * (plan->total_cost - plan->startup_cost);
|
/* also charge a cpu_operator_cost per row examined */
|
||||||
/* XXX what if subplan has been materialized? */
|
total->per_tuple += 0.50 * plan->plan_rows * cpu_operator_cost;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* assume we need all tuples */
|
/* assume we need all tuples */
|
||||||
subcost = plan->total_cost;
|
total->per_tuple += plan_run_cost;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Also account for subplan's startup cost.
|
||||||
|
* If the subplan is uncorrelated or undirect correlated,
|
||||||
|
* AND its topmost node is a Sort or Material node, assume
|
||||||
|
* that we'll only need to pay its startup cost once;
|
||||||
|
* otherwise assume we pay the startup cost every time.
|
||||||
|
*/
|
||||||
|
if (subplan->parParam == NIL &&
|
||||||
|
(IsA(plan, Sort) ||
|
||||||
|
IsA(plan, Material)))
|
||||||
|
{
|
||||||
|
total->startup += plan->startup_cost;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
total->per_tuple += plan->startup_cost;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*total += subcost;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return expression_tree_walker(node, cost_qual_eval_walker,
|
return expression_tree_walker(node, cost_qual_eval_walker,
|
||||||
@ -1388,7 +1466,7 @@ set_baserel_size_estimates(Query *root, RelOptInfo *rel)
|
|||||||
|
|
||||||
rel->rows = temp;
|
rel->rows = temp;
|
||||||
|
|
||||||
rel->baserestrictcost = cost_qual_eval(rel->baserestrictinfo);
|
cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo);
|
||||||
|
|
||||||
set_rel_width(root, rel);
|
set_rel_width(root, rel);
|
||||||
}
|
}
|
||||||
@ -1533,7 +1611,7 @@ set_function_size_estimates(Query *root, RelOptInfo *rel)
|
|||||||
|
|
||||||
rel->rows = temp;
|
rel->rows = temp;
|
||||||
|
|
||||||
rel->baserestrictcost = cost_qual_eval(rel->baserestrictinfo);
|
cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo);
|
||||||
|
|
||||||
set_rel_width(root, rel);
|
set_rel_width(root, rel);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.79 2002/12/17 01:18:25 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.80 2003/01/12 22:35:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -396,7 +396,7 @@ distribute_qual_to_rels(Query *root, Node *clause,
|
|||||||
|
|
||||||
restrictinfo->clause = (Expr *) clause;
|
restrictinfo->clause = (Expr *) clause;
|
||||||
restrictinfo->subclauseindices = NIL;
|
restrictinfo->subclauseindices = NIL;
|
||||||
restrictinfo->eval_cost = -1; /* not computed until needed */
|
restrictinfo->eval_cost.startup = -1; /* not computed until needed */
|
||||||
restrictinfo->this_selec = -1; /* not computed until needed */
|
restrictinfo->this_selec = -1; /* not computed until needed */
|
||||||
restrictinfo->mergejoinoperator = InvalidOid;
|
restrictinfo->mergejoinoperator = InvalidOid;
|
||||||
restrictinfo->left_sortop = InvalidOid;
|
restrictinfo->left_sortop = InvalidOid;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.84 2003/01/05 00:56:40 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.85 2003/01/12 22:35:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -853,7 +853,7 @@ adjust_inherited_attrs_mutator(Node *node,
|
|||||||
adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context);
|
adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context);
|
||||||
|
|
||||||
newinfo->subclauseindices = NIL;
|
newinfo->subclauseindices = NIL;
|
||||||
newinfo->eval_cost = -1; /* reset these too */
|
newinfo->eval_cost.startup = -1; /* reset these too */
|
||||||
newinfo->this_selec = -1;
|
newinfo->this_selec = -1;
|
||||||
newinfo->left_pathkey = NIL; /* and these */
|
newinfo->left_pathkey = NIL; /* and these */
|
||||||
newinfo->right_pathkey = NIL;
|
newinfo->right_pathkey = NIL;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.41 2002/11/24 21:52:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.42 2003/01/12 22:35:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -149,7 +149,8 @@ make_base_rel(Query *root, int relid)
|
|||||||
rel->joinrti = 0;
|
rel->joinrti = 0;
|
||||||
rel->joinrteids = NIL;
|
rel->joinrteids = NIL;
|
||||||
rel->baserestrictinfo = NIL;
|
rel->baserestrictinfo = NIL;
|
||||||
rel->baserestrictcost = 0;
|
rel->baserestrictcost.startup = 0;
|
||||||
|
rel->baserestrictcost.per_tuple = 0;
|
||||||
rel->outerjoinset = NIL;
|
rel->outerjoinset = NIL;
|
||||||
rel->joininfo = NIL;
|
rel->joininfo = NIL;
|
||||||
rel->index_outer_relids = NIL;
|
rel->index_outer_relids = NIL;
|
||||||
@ -363,7 +364,8 @@ build_join_rel(Query *root,
|
|||||||
joinrel->joinrteids = nconc(listCopy(outer_rel->joinrteids),
|
joinrel->joinrteids = nconc(listCopy(outer_rel->joinrteids),
|
||||||
inner_rel->joinrteids);
|
inner_rel->joinrteids);
|
||||||
joinrel->baserestrictinfo = NIL;
|
joinrel->baserestrictinfo = NIL;
|
||||||
joinrel->baserestrictcost = 0;
|
joinrel->baserestrictcost.startup = 0;
|
||||||
|
joinrel->baserestrictcost.per_tuple = 0;
|
||||||
joinrel->outerjoinset = NIL;
|
joinrel->outerjoinset = NIL;
|
||||||
joinrel->joininfo = NIL;
|
joinrel->joininfo = NIL;
|
||||||
joinrel->index_outer_relids = NIL;
|
joinrel->index_outer_relids = NIL;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.124 2002/12/17 01:18:35 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.125 2003/01/12 22:35:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -3757,6 +3757,7 @@ genericcostestimate(Query *root, RelOptInfo *rel,
|
|||||||
{
|
{
|
||||||
double numIndexTuples;
|
double numIndexTuples;
|
||||||
double numIndexPages;
|
double numIndexPages;
|
||||||
|
QualCost index_qual_cost;
|
||||||
List *selectivityQuals = indexQuals;
|
List *selectivityQuals = indexQuals;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3826,9 +3827,10 @@ genericcostestimate(Query *root, RelOptInfo *rel,
|
|||||||
* tuple. All the costs are assumed to be paid incrementally during
|
* tuple. All the costs are assumed to be paid incrementally during
|
||||||
* the scan.
|
* the scan.
|
||||||
*/
|
*/
|
||||||
*indexStartupCost = 0;
|
cost_qual_eval(&index_qual_cost, indexQuals);
|
||||||
|
*indexStartupCost = index_qual_cost.startup;
|
||||||
*indexTotalCost = numIndexPages +
|
*indexTotalCost = numIndexPages +
|
||||||
(cpu_index_tuple_cost + cost_qual_eval(indexQuals)) * numIndexTuples;
|
(cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic assumption about index correlation: there isn't any.
|
* Generic assumption about index correlation: there isn't any.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: relation.h,v 1.74 2002/12/12 15:49:40 tgl Exp $
|
* $Id: relation.h,v 1.75 2003/01/12 22:35:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -35,6 +35,16 @@ typedef enum CostSelector
|
|||||||
STARTUP_COST, TOTAL_COST
|
STARTUP_COST, TOTAL_COST
|
||||||
} CostSelector;
|
} CostSelector;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The cost estimate produced by cost_qual_eval() includes both a one-time
|
||||||
|
* (startup) cost, and a per-tuple cost.
|
||||||
|
*/
|
||||||
|
typedef struct QualCost
|
||||||
|
{
|
||||||
|
Cost startup; /* one-time cost */
|
||||||
|
Cost per_tuple; /* per-evaluation cost */
|
||||||
|
} QualCost;
|
||||||
|
|
||||||
/*----------
|
/*----------
|
||||||
* RelOptInfo
|
* RelOptInfo
|
||||||
* Per-relation information for planning/optimization
|
* Per-relation information for planning/optimization
|
||||||
@ -199,7 +209,7 @@ typedef struct RelOptInfo
|
|||||||
/* used by various scans and joins: */
|
/* used by various scans and joins: */
|
||||||
List *baserestrictinfo; /* RestrictInfo structures (if
|
List *baserestrictinfo; /* RestrictInfo structures (if
|
||||||
* base rel) */
|
* base rel) */
|
||||||
Cost baserestrictcost; /* cost of evaluating the above */
|
QualCost baserestrictcost; /* cost of evaluating the above */
|
||||||
Relids outerjoinset; /* integer list of base relids */
|
Relids outerjoinset; /* integer list of base relids */
|
||||||
List *joininfo; /* JoinInfo structures */
|
List *joininfo; /* JoinInfo structures */
|
||||||
|
|
||||||
@ -570,7 +580,7 @@ typedef struct RestrictInfo
|
|||||||
/* subclauseindices is a List of Lists of IndexOptInfos */
|
/* subclauseindices is a List of Lists of IndexOptInfos */
|
||||||
|
|
||||||
/* cache space for costs (currently only used for join clauses) */
|
/* cache space for costs (currently only used for join clauses) */
|
||||||
Cost eval_cost; /* eval cost of clause; -1 if not yet set */
|
QualCost eval_cost; /* eval cost of clause; -1 if not yet set */
|
||||||
Selectivity this_selec; /* selectivity; -1 if not yet set */
|
Selectivity this_selec; /* selectivity; -1 if not yet set */
|
||||||
|
|
||||||
/* valid if clause is mergejoinable, else InvalidOid: */
|
/* valid if clause is mergejoinable, else InvalidOid: */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: cost.h,v 1.49 2002/11/30 05:21:03 tgl Exp $
|
* $Id: cost.h,v 1.50 2003/01/12 22:35:29 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -83,7 +83,7 @@ extern void cost_hashjoin(Path *path, Query *root,
|
|||||||
Path *outer_path, Path *inner_path,
|
Path *outer_path, Path *inner_path,
|
||||||
List *restrictlist,
|
List *restrictlist,
|
||||||
List *hashclauses);
|
List *hashclauses);
|
||||||
extern Cost cost_qual_eval(List *quals);
|
extern void cost_qual_eval(QualCost *cost, List *quals);
|
||||||
extern void set_baserel_size_estimates(Query *root, RelOptInfo *rel);
|
extern void set_baserel_size_estimates(Query *root, RelOptInfo *rel);
|
||||||
extern void set_joinrel_size_estimates(Query *root, RelOptInfo *rel,
|
extern void set_joinrel_size_estimates(Query *root, RelOptInfo *rel,
|
||||||
RelOptInfo *outer_rel,
|
RelOptInfo *outer_rel,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user