From 3d09f6c5609da36270c77b24f87313eac94a7635 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 14 Jul 2003 22:35:54 +0000 Subject: [PATCH] Make cost estimates for SubqueryScan more realistic: charge cpu_tuple_cost for each row processed, and don't forget the evaluation cost of any restriction clauses attached to the node. Per discussion with Greg Stark. --- src/backend/optimizer/path/costsize.c | 34 ++++++++++++++++++++++++- src/backend/optimizer/plan/createplan.c | 19 +++++++++++--- src/backend/optimizer/util/pathnode.c | 6 ++--- src/include/optimizer/cost.h | 3 ++- 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 34a3aaf1c9..3011f687c5 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -49,7 +49,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.109 2003/06/29 23:05:04 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.110 2003/07/14 22:35:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -415,6 +415,38 @@ cost_tidscan(Path *path, Query *root, path->total_cost = startup_cost + run_cost; } +/* + * cost_subqueryscan + * Determines and returns the cost of scanning a subquery RTE. + */ +void +cost_subqueryscan(Path *path, RelOptInfo *baserel) +{ + Cost startup_cost; + Cost run_cost; + Cost cpu_per_tuple; + + /* Should only be applied to base relations that are subqueries */ + Assert(baserel->relid > 0); + Assert(baserel->rtekind == RTE_SUBQUERY); + + /* + * Cost of path is cost of evaluating the subplan, plus cost of + * evaluating any restriction clauses that will be attached to the + * SubqueryScan node, plus cpu_tuple_cost to account for selection + * and projection overhead. + */ + path->startup_cost = baserel->subplan->startup_cost; + path->total_cost = baserel->subplan->total_cost; + + startup_cost = baserel->baserestrictcost.startup; + cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple; + run_cost = cpu_per_tuple * baserel->tuples; + + path->startup_cost += startup_cost; + path->total_cost += startup_cost + run_cost; +} + /* * cost_functionscan * Determines and returns the cost of scanning a function RTE. diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 1cdc3628b2..79855b00c0 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.147 2003/06/29 23:05:04 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.148 2003/07/14 22:35:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -811,6 +811,8 @@ create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses) scan_relid, best_path->parent->subplan); + copy_path_costsize(&scan_plan->scan.plan, best_path); + return scan_plan; } @@ -1503,8 +1505,14 @@ make_subqueryscan(List *qptlist, SubqueryScan *node = makeNode(SubqueryScan); Plan *plan = &node->scan.plan; - /* cost is figured here for the convenience of prepunion.c */ + /* + * Cost is figured here for the convenience of prepunion.c. Note this + * is only correct for the case where qpqual is empty; otherwise caller + * should overwrite cost with a better estimate. + */ copy_plan_costsize(plan, subplan); + plan->total_cost += cpu_tuple_cost * subplan->plan_rows; + plan->targetlist = qptlist; plan->qual = qpqual; plan->lefttree = NULL; @@ -1540,7 +1548,11 @@ make_append(List *appendplans, bool isTarget, List *tlist) Plan *plan = &node->plan; List *subnode; - /* compute costs from subplan costs */ + /* + * Compute cost as sum of subplan costs. We charge nothing extra for + * the Append itself, which perhaps is too optimistic, but since it + * doesn't do any selection or projection, it is a pretty cheap node. + */ plan->startup_cost = 0; plan->total_cost = 0; plan->plan_rows = 0; @@ -1556,6 +1568,7 @@ make_append(List *appendplans, bool isTarget, List *tlist) if (plan->plan_width < subplan->plan_width) plan->plan_width = subplan->plan_width; } + plan->targetlist = tlist; plan->qual = NIL; plan->lefttree = NULL; diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 9e919079cc..19198bf249 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.91 2003/06/29 23:05:04 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.92 2003/07/14 22:35:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -686,9 +686,7 @@ create_subqueryscan_path(RelOptInfo *rel, List *pathkeys) pathnode->parent = rel; pathnode->pathkeys = pathkeys; - /* just copy the subplan's cost estimates */ - pathnode->startup_cost = rel->subplan->startup_cost; - pathnode->total_cost = rel->subplan->total_cost; + cost_subqueryscan(pathnode, rel); return pathnode; } diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index 45c83191a2..ad2122f46e 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: cost.h,v 1.53 2003/06/11 15:01:15 momjian Exp $ + * $Id: cost.h,v 1.54 2003/07/14 22:35:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -56,6 +56,7 @@ extern void cost_index(Path *path, Query *root, List *indexQuals, bool is_injoin); extern void cost_tidscan(Path *path, Query *root, RelOptInfo *baserel, List *tideval); +extern void cost_subqueryscan(Path *path, RelOptInfo *baserel); extern void cost_functionscan(Path *path, Query *root, RelOptInfo *baserel); extern void cost_sort(Path *path, Query *root,