Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd4ce5a4

Browse files
committed
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 ormaterialized sub-selects.
1 parentd51260a commitd4ce5a4

File tree

8 files changed

+164
-71
lines changed

8 files changed

+164
-71
lines changed

‎doc/src/sgml/indexcost.sgml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/Attic/indexcost.sgml,v 2.12 2002/08/22 00:01:40 tgl Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/Attic/indexcost.sgml,v 2.13 2003/01/12 22:35:29 tgl Exp $
33
-->
44

55
<chapter id="indexcost">
@@ -237,9 +237,10 @@ amcostestimate (Query *root,
237237
* Also, we charge for evaluation of the indexquals at each index tuple.
238238
* All the costs are assumed to be paid incrementally during the scan.
239239
*/
240-
*indexStartupCost = 0;
240+
cost_qual_eval(&index_qual_cost, indexQuals);
241+
*indexStartupCost = index_qual_cost.startup;
241242
*indexTotalCost = numIndexPages +
242-
(cpu_index_tuple_cost +cost_qual_eval(indexQuals)) * numIndexTuples;
243+
(cpu_index_tuple_cost +index_qual_cost.per_tuple) * numIndexTuples;
243244
</programlisting>
244245
</para>
245246
</step>

‎src/backend/optimizer/path/costsize.c

Lines changed: 131 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* Portions Copyright (c) 1994, Regents of the University of California
4343
*
4444
* IDENTIFICATION
45-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.98 2002/12/30 15:21:21 tgl Exp $
45+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.99 2003/01/12 22:35:29 tgl Exp $
4646
*
4747
*-------------------------------------------------------------------------
4848
*/
@@ -87,7 +87,7 @@ boolenable_hashjoin = true;
8787

8888
staticSelectivityestimate_hash_bucketsize(Query*root,Var*var,
8989
intnbuckets);
90-
staticboolcost_qual_eval_walker(Node*node,Cost*total);
90+
staticboolcost_qual_eval_walker(Node*node,QualCost*total);
9191
staticSelectivityapprox_selectivity(Query*root,List*quals);
9292
staticvoidset_rel_width(Query*root,RelOptInfo*rel);
9393
staticdoublerelation_byte_size(doubletuples,intwidth);
@@ -131,7 +131,8 @@ cost_seqscan(Path *path, Query *root,
131131
run_cost+=baserel->pages;/* sequential fetches with cost 1.0 */
132132

133133
/* CPU costs */
134-
cpu_per_tuple=cpu_tuple_cost+baserel->baserestrictcost;
134+
startup_cost+=baserel->baserestrictcost.startup;
135+
cpu_per_tuple=cpu_tuple_cost+baserel->baserestrictcost.per_tuple;
135136
run_cost+=cpu_per_tuple*baserel->tuples;
136137

137138
path->startup_cost=startup_cost;
@@ -344,17 +345,25 @@ cost_index(Path *path, Query *root,
344345
*
345346
* Normally the indexquals will be removed from the list of restriction
346347
* clauses that we have to evaluate as qpquals, so we should subtract
347-
* their costs from baserestrictcost. XXX For a lossy index, not all
348-
* the quals will be removed and so we really shouldn't subtract their
349-
* costs; but detecting that seems more expensive than it's worth.
350-
* Also, if we are doing a join then some of the indexquals are join
351-
* clauses and shouldn't be subtracted. Rather than work out exactly
352-
* how much to subtract, we don't subtract anything.
348+
* their costs from baserestrictcost. But if we are doing a join then
349+
* some of the indexquals are join clauses and shouldn't be subtracted.
350+
* Rather than work out exactly how much to subtract, we don't subtract
351+
* anything.
352+
*
353+
* XXX For a lossy index, not all the quals will be removed and so we
354+
* really shouldn't subtract their costs; but detecting that seems more
355+
* expensive than it's worth.
353356
*/
354-
cpu_per_tuple=cpu_tuple_cost+baserel->baserestrictcost;
357+
startup_cost+=baserel->baserestrictcost.startup;
358+
cpu_per_tuple=cpu_tuple_cost+baserel->baserestrictcost.per_tuple;
355359

356360
if (!is_injoin)
357-
cpu_per_tuple-=cost_qual_eval(indexQuals);
361+
{
362+
QualCostindex_qual_cost;
363+
364+
cost_qual_eval(&index_qual_cost,indexQuals);
365+
cpu_per_tuple-=index_qual_cost.per_tuple;
366+
}
358367

359368
run_cost+=cpu_per_tuple*tuples_fetched;
360369

@@ -386,7 +395,8 @@ cost_tidscan(Path *path, Query *root,
386395
run_cost+=random_page_cost*ntuples;
387396

388397
/* CPU costs */
389-
cpu_per_tuple=cpu_tuple_cost+baserel->baserestrictcost;
398+
startup_cost+=baserel->baserestrictcost.startup;
399+
cpu_per_tuple=cpu_tuple_cost+baserel->baserestrictcost.per_tuple;
390400
run_cost+=cpu_per_tuple*ntuples;
391401

392402
path->startup_cost=startup_cost;
@@ -416,7 +426,8 @@ cost_functionscan(Path *path, Query *root, RelOptInfo *baserel)
416426
cpu_per_tuple=cpu_operator_cost;
417427

418428
/* Add scanning CPU costs */
419-
cpu_per_tuple+=cpu_tuple_cost+baserel->baserestrictcost;
429+
startup_cost+=baserel->baserestrictcost.startup;
430+
cpu_per_tuple+=cpu_tuple_cost+baserel->baserestrictcost.per_tuple;
420431
run_cost+=cpu_per_tuple*baserel->tuples;
421432

422433
path->startup_cost=startup_cost;
@@ -656,6 +667,7 @@ cost_nestloop(Path *path, Query *root,
656667
Coststartup_cost=0;
657668
Costrun_cost=0;
658669
Costcpu_per_tuple;
670+
QualCostrestrict_qual_cost;
659671
doublentuples;
660672

661673
if (!enable_nestloop)
@@ -703,7 +715,9 @@ cost_nestloop(Path *path, Query *root,
703715
ntuples *=outer_path->parent->rows;
704716

705717
/* CPU costs */
706-
cpu_per_tuple=cpu_tuple_cost+cost_qual_eval(restrictlist);
718+
cost_qual_eval(&restrict_qual_cost,restrictlist);
719+
startup_cost+=restrict_qual_cost.startup;
720+
cpu_per_tuple=cpu_tuple_cost+restrict_qual_cost.per_tuple;
707721
run_cost+=cpu_per_tuple*ntuples;
708722

709723
path->startup_cost=startup_cost;
@@ -736,6 +750,7 @@ cost_mergejoin(Path *path, Query *root,
736750
Coststartup_cost=0;
737751
Costrun_cost=0;
738752
Costcpu_per_tuple;
753+
QualCostrestrict_qual_cost;
739754
RestrictInfo*firstclause;
740755
Var*leftvar;
741756
doubleouter_rows,
@@ -850,7 +865,9 @@ cost_mergejoin(Path *path, Query *root,
850865
outer_path->parent->rows*inner_path->parent->rows;
851866

852867
/* CPU costs */
853-
cpu_per_tuple=cpu_tuple_cost+cost_qual_eval(restrictlist);
868+
cost_qual_eval(&restrict_qual_cost,restrictlist);
869+
startup_cost+=restrict_qual_cost.startup;
870+
cpu_per_tuple=cpu_tuple_cost+restrict_qual_cost.per_tuple;
854871
run_cost+=cpu_per_tuple*ntuples;
855872

856873
path->startup_cost=startup_cost;
@@ -878,6 +895,7 @@ cost_hashjoin(Path *path, Query *root,
878895
Coststartup_cost=0;
879896
Costrun_cost=0;
880897
Costcpu_per_tuple;
898+
QualCostrestrict_qual_cost;
881899
doublentuples;
882900
doubleouterbytes=relation_byte_size(outer_path->parent->rows,
883901
outer_path->parent->width);
@@ -984,7 +1002,9 @@ cost_hashjoin(Path *path, Query *root,
9841002
outer_path->parent->rows*inner_path->parent->rows;
9851003

9861004
/* CPU costs */
987-
cpu_per_tuple=cpu_tuple_cost+cost_qual_eval(restrictlist);
1005+
cost_qual_eval(&restrict_qual_cost,restrictlist);
1006+
startup_cost+=restrict_qual_cost.startup;
1007+
cpu_per_tuple=cpu_tuple_cost+restrict_qual_cost.per_tuple;
9881008
run_cost+=cpu_per_tuple*ntuples;
9891009

9901010
/*
@@ -1185,16 +1205,20 @@ estimate_hash_bucketsize(Query *root, Var *var, int nbuckets)
11851205

11861206
/*
11871207
* cost_qual_eval
1188-
*Estimate the CPUcost of evaluating a WHERE clause (once).
1208+
*Estimate the CPUcosts of evaluating a WHERE clause.
11891209
*The input can be either an implicitly-ANDed list of boolean
11901210
*expressions, or a list of RestrictInfo nodes.
1211+
*The result includes both a one-time (startup) component,
1212+
*and a per-evaluation component.
11911213
*/
1192-
Cost
1193-
cost_qual_eval(List*quals)
1214+
void
1215+
cost_qual_eval(QualCost*cost,List*quals)
11941216
{
1195-
Costtotal=0;
11961217
List*l;
11971218

1219+
cost->startup=0;
1220+
cost->per_tuple=0;
1221+
11981222
/* We don't charge any cost for the implicit ANDing at top level ... */
11991223

12001224
foreach(l,quals)
@@ -1205,31 +1229,32 @@ cost_qual_eval(List *quals)
12051229
* RestrictInfo nodes contain an eval_cost field reserved for this
12061230
* routine's use, so that it's not necessary to evaluate the qual
12071231
* clause's cost more than once. If the clause's cost hasn't been
1208-
* computed yet, the field will contain -1.
1232+
* computed yet, the field's startup value will contain -1.
12091233
*/
12101234
if (qual&&IsA(qual,RestrictInfo))
12111235
{
12121236
RestrictInfo*restrictinfo= (RestrictInfo*)qual;
12131237

1214-
if (restrictinfo->eval_cost<0)
1238+
if (restrictinfo->eval_cost.startup<0)
12151239
{
1216-
restrictinfo->eval_cost=0;
1240+
restrictinfo->eval_cost.startup=0;
1241+
restrictinfo->eval_cost.per_tuple=0;
12171242
cost_qual_eval_walker((Node*)restrictinfo->clause,
12181243
&restrictinfo->eval_cost);
12191244
}
1220-
total+=restrictinfo->eval_cost;
1245+
cost->startup+=restrictinfo->eval_cost.startup;
1246+
cost->per_tuple+=restrictinfo->eval_cost.per_tuple;
12211247
}
12221248
else
12231249
{
12241250
/* If it's a bare expression, must always do it the hard way */
1225-
cost_qual_eval_walker(qual,&total);
1251+
cost_qual_eval_walker(qual,cost);
12261252
}
12271253
}
1228-
returntotal;
12291254
}
12301255

12311256
staticbool
1232-
cost_qual_eval_walker(Node*node,Cost*total)
1257+
cost_qual_eval_walker(Node*node,QualCost*total)
12331258
{
12341259
if (node==NULL)
12351260
return false;
@@ -1246,43 +1271,96 @@ cost_qual_eval_walker(Node *node, Cost *total)
12461271
if (IsA(node,FuncExpr)||
12471272
IsA(node,OpExpr)||
12481273
IsA(node,DistinctExpr))
1249-
*total+=cpu_operator_cost;
1274+
{
1275+
total->per_tuple+=cpu_operator_cost;
1276+
}
1277+
elseif (IsA(node,SubLink))
1278+
{
1279+
/* This routine should not be applied to un-planned expressions */
1280+
elog(ERROR,"cost_qual_eval: can't handle unplanned sub-select");
1281+
}
12501282
elseif (IsA(node,SubPlan))
12511283
{
12521284
/*
1253-
* A subplan node in an expression indicates that the
1254-
* subplan will be executed on each evaluation, so charge
1255-
* accordingly. (We assume that sub-selects that can be
1256-
* executed as InitPlans have already been removed from
1257-
* the expression.)
1285+
* A subplan node in an expression typically indicates that the
1286+
* subplan will be executed on each evaluation, so charge accordingly.
1287+
* (Sub-selects that can be executed as InitPlans have already been
1288+
* removed from the expression.)
1289+
*
1290+
* An exception occurs when we have decided we can implement the
1291+
* subplan by hashing.
12581292
*
1259-
* NOTE: this logic should agree with the estimates used by
1260-
* make_subplan() in plan/subselect.c.
12611293
*/
12621294
SubPlan*subplan= (SubPlan*)node;
12631295
Plan*plan=subplan->plan;
1264-
Costsubcost;
12651296

1266-
if (subplan->subLinkType==EXISTS_SUBLINK)
1297+
if (subplan->useHashTable)
12671298
{
1268-
/* we only need to fetch 1 tuple */
1269-
subcost=plan->startup_cost+
1270-
(plan->total_cost-plan->startup_cost) /plan->plan_rows;
1271-
}
1272-
elseif (subplan->subLinkType==ALL_SUBLINK||
1273-
subplan->subLinkType==ANY_SUBLINK)
1274-
{
1275-
/* assume we need 50% of the tuples */
1276-
subcost=plan->startup_cost+
1277-
0.50* (plan->total_cost-plan->startup_cost);
1278-
/* XXX what if subplan has been materialized? */
1299+
/*
1300+
* If we are using a hash table for the subquery outputs, then
1301+
* the cost of evaluating the query is a one-time cost.
1302+
* We charge one cpu_operator_cost per tuple for the work of
1303+
* loading the hashtable, too.
1304+
*/
1305+
total->startup+=plan->total_cost+
1306+
cpu_operator_cost*plan->plan_rows;
1307+
/*
1308+
* The per-tuple costs include the cost of evaluating the
1309+
* lefthand expressions, plus the cost of probing the hashtable.
1310+
* Recursion into the exprs list will handle the lefthand
1311+
* expressions properly, and will count one cpu_operator_cost
1312+
* for each comparison operator. That is probably too low for
1313+
* the probing cost, but it's hard to make a better estimate,
1314+
* so live with it for now.
1315+
*/
12791316
}
12801317
else
12811318
{
1282-
/* assume we need all tuples */
1283-
subcost=plan->total_cost;
1319+
/*
1320+
* Otherwise we will be rescanning the subplan output on each
1321+
* evaluation. We need to estimate how much of the output
1322+
* we will actually need to scan. NOTE: this logic should
1323+
* agree with the estimates used by make_subplan() in
1324+
* plan/subselect.c.
1325+
*/
1326+
Costplan_run_cost=plan->total_cost-plan->startup_cost;
1327+
1328+
if (subplan->subLinkType==EXISTS_SUBLINK)
1329+
{
1330+
/* we only need to fetch 1 tuple */
1331+
total->per_tuple+=plan_run_cost /plan->plan_rows;
1332+
}
1333+
elseif (subplan->subLinkType==ALL_SUBLINK||
1334+
subplan->subLinkType==ANY_SUBLINK)
1335+
{
1336+
/* assume we need 50% of the tuples */
1337+
total->per_tuple+=0.50*plan_run_cost;
1338+
/* also charge a cpu_operator_cost per row examined */
1339+
total->per_tuple+=0.50*plan->plan_rows*cpu_operator_cost;
1340+
}
1341+
else
1342+
{
1343+
/* assume we need all tuples */
1344+
total->per_tuple+=plan_run_cost;
1345+
}
1346+
/*
1347+
* Also account for subplan's startup cost.
1348+
* If the subplan is uncorrelated or undirect correlated,
1349+
* AND its topmost node is a Sort or Material node, assume
1350+
* that we'll only need to pay its startup cost once;
1351+
* otherwise assume we pay the startup cost every time.
1352+
*/
1353+
if (subplan->parParam==NIL&&
1354+
(IsA(plan,Sort)||
1355+
IsA(plan,Material)))
1356+
{
1357+
total->startup+=plan->startup_cost;
1358+
}
1359+
else
1360+
{
1361+
total->per_tuple+=plan->startup_cost;
1362+
}
12841363
}
1285-
*total+=subcost;
12861364
}
12871365

12881366
returnexpression_tree_walker(node,cost_qual_eval_walker,
@@ -1388,7 +1466,7 @@ set_baserel_size_estimates(Query *root, RelOptInfo *rel)
13881466

13891467
rel->rows=temp;
13901468

1391-
rel->baserestrictcost=cost_qual_eval(rel->baserestrictinfo);
1469+
cost_qual_eval(&rel->baserestrictcost,rel->baserestrictinfo);
13921470

13931471
set_rel_width(root,rel);
13941472
}
@@ -1533,7 +1611,7 @@ set_function_size_estimates(Query *root, RelOptInfo *rel)
15331611

15341612
rel->rows=temp;
15351613

1536-
rel->baserestrictcost=cost_qual_eval(rel->baserestrictinfo);
1614+
cost_qual_eval(&rel->baserestrictcost,rel->baserestrictinfo);
15371615

15381616
set_rel_width(root,rel);
15391617
}

‎src/backend/optimizer/plan/initsplan.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.79 2002/12/17 01:18:25 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.80 2003/01/12 22:35:29 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -396,7 +396,7 @@ distribute_qual_to_rels(Query *root, Node *clause,
396396

397397
restrictinfo->clause= (Expr*)clause;
398398
restrictinfo->subclauseindices=NIL;
399-
restrictinfo->eval_cost=-1;/* not computed until needed */
399+
restrictinfo->eval_cost.startup=-1;/* not computed until needed */
400400
restrictinfo->this_selec=-1;/* not computed until needed */
401401
restrictinfo->mergejoinoperator=InvalidOid;
402402
restrictinfo->left_sortop=InvalidOid;

‎src/backend/optimizer/prep/prepunion.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
*
1616
* IDENTIFICATION
17-
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.84 2003/01/05 00:56:40 tgl Exp $
17+
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.85 2003/01/12 22:35:29 tgl Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -853,7 +853,7 @@ adjust_inherited_attrs_mutator(Node *node,
853853
adjust_inherited_attrs_mutator((Node*)oldinfo->clause,context);
854854

855855
newinfo->subclauseindices=NIL;
856-
newinfo->eval_cost=-1;/* reset these too */
856+
newinfo->eval_cost.startup=-1;/* reset these too */
857857
newinfo->this_selec=-1;
858858
newinfo->left_pathkey=NIL;/* and these */
859859
newinfo->right_pathkey=NIL;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp