verbose cost estimate
Jeff said:
/messages/by-id/CAMkU=1zBJNVo2DGYBgLJqpu8fyjCE_ys+msr6pOEoiwA7y5jrA@mail.gmail.com
|What would I find very useful is a verbosity option to get the cost
|estimates expressed as a multiplier of each *_cost parameter, rather than
|just as a scalar.
I guess the goal is something like
EXPLAIN(COSTS, VERBOSE) -- or some new option?
..would show something like
Seq Scan on public.sites (cost=0.00..2.90 rows=160 width=107)
Total tosts: Seq page: 1.01 Random page: 1.23 CPU tuple: .05 CPU oper: .01
Startup cost: [...]
It seems to me that's "just" a matter of redefining Cost and fixing everything that breaks:
struct Cost {
double seq, rand;
double cpu_tuple, cpu_index_tuple, cpu_oper;
double parallel_setup; // This is probably always in startup_cost and never in run_cost
double parallel_tuple; // This is probably always in run_cost and never in startup_cost
double disable;
};
I'm perhaps 50% done with that - is there some agreement that's a desirable
goal and a good way to do it ?
To give an idea what I'm doing, there's a bunch of stuff like this:
- if (path1->startup_cost < path2->startup_cost)
+ if (cost_asscalar(&path1->startup_cost) < cost_asscalar(&path2->startup_cost))
- qual_arg_cost += index_qual_cost.startup + index_qual_cost.per_tuple;
+ cost_add2(&qual_arg_cost, &index_qual_cost.startup, &index_qual_cost.per_tuple);
- if (cost.per_tuple > 10 * cpu_operator_cost)
+ if (cost_isgt_scalar(&cost.per_tuple, 10 * cpu_operator_cost))
And a great deal of stuff like this:
- run_cost += cpu_run_cost;
+ cost_add(&run_cost, &cpu_run_cost);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->pathtarget->cost.startup;
- run_cost += path->pathtarget->cost.per_tuple * path->rows;
+ cost_add(&startup_cost, &path->pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->pathtarget->cost.per_tuple, path->rows);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
As I've written it, that's somewhat different from Jeff's suggestion, as all
the entries in my struct are in units of cost. That seems easier due to (for
example) per-tablespace IO costs.
I'd rather know sooner than later if there's a better way.
Justin
Justin Pryzby <pryzby@telsasoft.com> writes:
Jeff said:
|What would I find very useful is a verbosity option to get the cost
|estimates expressed as a multiplier of each *_cost parameter, rather than
|just as a scalar.
It seems to me that's "just" a matter of redefining Cost and fixing everything that breaks:
struct Cost {
double seq, rand;
double cpu_tuple, cpu_index_tuple, cpu_oper;
double parallel_setup; // This is probably always in startup_cost and never in run_cost
double parallel_tuple; // This is probably always in run_cost and never in startup_cost
double disable;
};
I'm perhaps 50% done with that - is there some agreement that's a desirable
goal and a good way to do it ?
No, I think this will get rejected out of hand. The implications for
the planner's speed and memory consumption seem quite unacceptable
for the size of the benefit. What you're showing above probably
doubles the size of most Paths, and the added cycles in hot-spots
like add_path seem pretty daunting.
We had earlier discussions about just breaking out the disable_cost,
and even that didn't look very promising as a practical matter :-(.
Nobody is willing to give up even small slowdowns in everyday
planning speed for corner-case needs like these.
One idea that would alleviate some of the problems is to keep the
net cost as-is, and just add a separate struct of broken-down
cost. Then, for example, add_path doesn't change at all. But
this makes the memory consumption angle even worse.
Like Jeff, I've occasionally wished for info like this. But not
often, and not hard enough that I think the cost of getting it
would be justified.
Something that might be useful when you do want this info is to
change one of the cost parameters by some small delta, rerun the
plan, and see how much the total cost changes; that gives you a
local slope of the sensitivity function. Repeat as needed for
other cost parameters. The tedious part is probably verifying
that the shape of the plan didn't change (else the cost comparison
isn't telling you what you want). Perhaps building a tool
to automate that idea would be worthwhile.
regards, tom lane
+1, adding that sort of structure to Cost would get rejected out of hand.
however, having a 'disabled' bit be part of the cost structure is something
that I would support. This has been discussed previously, but even adding
one bit to Cost doesn't have everyone's support. The purpose of a disabled
bit would be to distinguish plans that had no disable_cost added to them
from plans that did so that the planner can choose the minimum cost
non-disabled plan, if any such plan exists, or choose the minimum cost plan
otherwise. A disable count could be used, but even a bool would probably
suffice.
thank you,
/Jim F
-----
Jim Finnerty, AWS, Amazon Aurora PostgreSQL
--
Sent from: https://www.postgresql-archive.org/PostgreSQL-hackers-f1928748.html
Jim Finnerty <jfinnert@amazon.com> writes:
+1, adding that sort of structure to Cost would get rejected out of hand.
however, having a 'disabled' bit be part of the cost structure is something
that I would support. This has been discussed previously, but even adding
one bit to Cost doesn't have everyone's support. The purpose of a disabled
bit would be to distinguish plans that had no disable_cost added to them
from plans that did so that the planner can choose the minimum cost
non-disabled plan, if any such plan exists, or choose the minimum cost plan
otherwise. A disable count could be used, but even a bool would probably
suffice.
If we did go that route, I think a disable count would be the right thing.
It wouldn't take up any more space than a bool, probably, once you account
for padding overhead. And the code impact in hotspots like add_path would
be just about the same too. The advantage of a count is that, for
example, if you have enable_seqscan off then a path containing three
seqscans could be considered inferior to one with two; but if we have
only a bool then we can't tell the difference.
(Having said that, I'm still about -0.5 or so on the idea. But if
we do it, we should do a count.)
regards, tom lane
On Mon, Dec 9, 2019 at 11:21 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
If we did go that route, I think a disable count would be the right thing.
It wouldn't take up any more space than a bool, probably, once you account
for padding overhead. And the code impact in hotspots like add_path would
be just about the same too. The advantage of a count is that, for
example, if you have enable_seqscan off then a path containing three
seqscans could be considered inferior to one with two; but if we have
only a bool then we can't tell the difference.
I'm not sure that I buy the idea that a disable count wouldn't take up
any more space. A Boolean could even be represented as a flag inside
of a bitmask, taking up just one bit. But even if you used a whole
byte for it, in the long term, that's going to be cheaper; people
around here are not blind to the value of filling in holes left by
padding.
I do agree that an integer would give us more accurate planning. The
question in my mind is whether we care. It's not crazy to say that
disabling is more for testing than real use, that it's best effort,
and that once we give up on it, we give up completely -- which would
make a bool sufficient. Now the contrary position that we want to be
more accurate than that is not crazy either, and it's easy to see why
that would be more convenient with a complex plan.
But the real issue there, in my view, is that there's no way to
disable certain kinds of plans for just part of a query. Nor is there
any way to politely inform the planner that its idea of how many rows
a certain scan or join will return is bollocks, and let it know the
real number. There's just no way at all - except in limited cases,
some unprincipled hacks - to give the planner that kind of guidance,
suggestion, recommendation, urging, advice, clue, inkling, indicator,
or, you know, whatever other word we could use to describe that sort
of thing. So we're left with crude tools that affect the whole query.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Sat, Dec 07, 2019 at 11:34:12AM -0500, Tom Lane wrote:
Justin Pryzby <pryzby@telsasoft.com> writes:
Jeff said:
|What would I find very useful is a verbosity option to get the cost
|estimates expressed as a multiplier of each *_cost parameter, rather than
|just as a scalar.It seems to me that's "just" a matter of redefining Cost and fixing everything that breaks:
struct Cost {
double seq, rand;
double cpu_tuple, cpu_index_tuple, cpu_oper;
double parallel_setup; // This is probably always in startup_cost and never in run_cost
double parallel_tuple; // This is probably always in run_cost and never in startup_cost
double disable;
};I'm perhaps 50% done with that - is there some agreement that's a desirable
goal and a good way to do it ?No, I think this will get rejected out of hand. The implications for
the planner's speed and memory consumption seem quite unacceptable
for the size of the benefit. What you're showing above probably
doubles the size of most Paths, and the added cycles in hot-spots
like add_path seem pretty daunting.
Yeah, that's an issue. But I have to admit my main issue with this
proposal is that I have no idea how I'd interpret this Cost. I mean,
what do the fields express for different types of paths? How do they
contribute to the actual cost of that path?
What I regularly wish to know the parts of the cost for individual
paths: how much is the I/O (and maybe some extra bits about caching,
random and sequential I/O), cost of quals/functions, and so on. But this
info is inherently path-specific, it makes little sense to include that
into the regular Path struct. Perhaps a path-specific struct, referenced
from the path and built only with verbose explain would be fine?
regards
--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Mon, 9 Dec 2019 at 17:14, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote:
On Sat, Dec 07, 2019 at 11:34:12AM -0500, Tom Lane wrote:
Justin Pryzby <pryzby@telsasoft.com> writes:
Jeff said:
|What would I find very useful is a verbosity option to get the cost
|estimates expressed as a multiplier of each *_cost parameter, rather than
|just as a scalar.It seems to me that's "just" a matter of redefining Cost and fixing everything that breaks:
struct Cost {
double seq, rand;
double cpu_tuple, cpu_index_tuple, cpu_oper;
double parallel_setup; // This is probably always in startup_cost and never in run_cost
double parallel_tuple; // This is probably always in run_cost and never in startup_cost
double disable;
};I'm perhaps 50% done with that - is there some agreement that's a desirable
goal and a good way to do it ?No, I think this will get rejected out of hand. The implications for
the planner's speed and memory consumption seem quite unacceptable
for the size of the benefit. What you're showing above probably
doubles the size of most Paths, and the added cycles in hot-spots
like add_path seem pretty daunting.Yeah, that's an issue. But I have to admit my main issue with this
proposal is that I have no idea how I'd interpret this Cost. I mean,
what do the fields express for different types of paths? How do they
contribute to the actual cost of that path?
What I think users would be able to do with this info is understand
which parameter to tweak to raise the estimated cost of the node.
Everyone knows if you see a index scan is being used but is taking
longer than a sequential scan then you might try raising
random_page_cost. But I rarely see people tweaking the more "exotic"
parameters like operator_tuple_cost or index_tuple_cost and when they
do they aren't really sure what nodes they're affecting...
I remember planning to do a very similar thing back in the 8.3 era and
never getting around to it. You could imaging even storing these for
the overall plan in the logs and building a large matrix of actual
execution values versus these broken out individual costs. Then it
becomes a standard linear optimization problem to find the optimal
values for each parameter to minimize inaccurate plan estimates (and
to identify cases where there are outliers).
--
greg
Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:
... Perhaps a path-specific struct, referenced
from the path and built only with verbose explain would be fine?
How would that work, given that the planner doesn't know whether its
output is going to get explained? With features like the plan cache
and auto_explain in mind, it's very hard to see how you avoid having
to save the information always.
regards, tom lane
On Mon, Dec 09, 2019 at 05:27:01PM -0500, Greg Stark wrote:
On Mon, 9 Dec 2019 at 17:14, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote:
On Sat, Dec 07, 2019 at 11:34:12AM -0500, Tom Lane wrote:
Justin Pryzby <pryzby@telsasoft.com> writes:
Jeff said:
|What would I find very useful is a verbosity option to get the cost
|estimates expressed as a multiplier of each *_cost parameter, rather than
|just as a scalar.It seems to me that's "just" a matter of redefining Cost and fixing everything that breaks:
struct Cost {
double seq, rand;
double cpu_tuple, cpu_index_tuple, cpu_oper;
double parallel_setup; // This is probably always in startup_cost and never in run_cost
double parallel_tuple; // This is probably always in run_cost and never in startup_cost
double disable;
};I'm perhaps 50% done with that - is there some agreement that's a desirable
goal and a good way to do it ?No, I think this will get rejected out of hand. The implications for
the planner's speed and memory consumption seem quite unacceptable
for the size of the benefit. What you're showing above probably
doubles the size of most Paths, and the added cycles in hot-spots
like add_path seem pretty daunting.Yeah, that's an issue. But I have to admit my main issue with this
proposal is that I have no idea how I'd interpret this Cost. I mean,
what do the fields express for different types of paths? How do they
contribute to the actual cost of that path?What I think users would be able to do with this info is understand
which parameter to tweak to raise the estimated cost of the node.Everyone knows if you see a index scan is being used but is taking
longer than a sequential scan then you might try raising
random_page_cost. But I rarely see people tweaking the more "exotic"
parameters like operator_tuple_cost or index_tuple_cost and when they
do they aren't really sure what nodes they're affecting...
Well, but that's kinda my point - how would you know that you need to
increase random_page_cost, or how big influence it has? The total is a
fairly non-trivial combination of various cost parameters, effective
cache size etc. Maybe I just don't understand how the cost is split into
those pieces, named the same as the cost GUCs ...
I remember planning to do a very similar thing back in the 8.3 era and
never getting around to it. You could imaging even storing these for
the overall plan in the logs and building a large matrix of actual
execution values versus these broken out individual costs. Then it
becomes a standard linear optimization problem to find the optimal
values for each parameter to minimize inaccurate plan estimates (and
to identify cases where there are outliers).
Maybe, but that's for one query. If you do this for many queries, the
results may be easily contradicting, no?
regards
--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Mon, Dec 09, 2019 at 05:40:40PM -0500, Tom Lane wrote:
Tomas Vondra <tomas.vondra@2ndquadrant.com> writes:
... Perhaps a path-specific struct, referenced
from the path and built only with verbose explain would be fine?How would that work, given that the planner doesn't know whether its
output is going to get explained? With features like the plan cache
and auto_explain in mind, it's very hard to see how you avoid having
to save the information always.
I don't know, but my assumption is that this information would be needed
only very rarely. So maybe we could pass a flag enabling this to the
planner when executed from explain, and disable storing the plan in the
plan cache, or something. And the additional info would be only
available when explicitly requested using an extra EXPLAIN option.
So for example auto_explain would not really show this (or it might get
an extra option, with additional overhead).
regards
--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Tue, Dec 10, 2019 at 12:25:46AM +0100, Tomas Vondra wrote:
Everyone knows if you see a index scan is being used but is taking
longer than a sequential scan then you might try raising
random_page_cost. But I rarely see people tweaking the more "exotic"
parameters like operator_tuple_cost or index_tuple_cost and when they
do they aren't really sure what nodes they're affecting...Well, but that's kinda my point - how would you know that you need to
increase random_page_cost, or how big influence it has? The total is a
fairly non-trivial combination of various cost parameters, effective
cache size etc. Maybe I just don't understand how the cost is split into
those pieces, named the same as the cost GUCs ...
Everything which right now does:
|cost += something*random_page_cost
..ends up (via a macro):
cost.random_page_cost += random_page_cost
And everything which does:
|cost1 += cost2
..ends up doing the same for each of the component members.
99% of this falls into place trivially.
I'm attaching a patch which is perhaps 95% working; various plans have changed,
so I gather there's at least a few bugs.
There's probably a few things which could be improved:
Probably some "Costs" should be simple doubles if they're only ever multiples
of a single cost parameter.
Maybe someone will say that Cost should be a typedef to a struct* rather than a struct.
Maybe I should get rid of cost_islt/isgt and just use cost_asscalar().
Seems like parallel_setup_cost and disable_cost could be booleans.
Justin
Attachments:
0001-Make-Cost-a-structure.patchtext/x-diff; charset=us-asciiDownload
From a93e84eed0bc792be7acdab434671bea25c0b7ee Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryzbyj@telsasoft.com>
Date: Fri, 6 Dec 2019 21:38:02 -0600
Subject: [PATCH] Make "Cost" a structure..
..to allow "Explain" to show its members.
As mentioned by Jeff here:
https://www.postgresql.org/message-id/CAMkU%3D1zBJNVo2DGYBgLJqpu8fyjCE_ys%2Bmsr6pOEoiwA7y5jrA%40mail.gmail.com
---
src/backend/commands/explain.c | 65 +-
src/backend/executor/nodeHashjoin.c | 3 +-
src/backend/executor/nodeSubplan.c | 9 +-
src/backend/nodes/equalfuncs.c | 7 +-
src/backend/nodes/outfuncs.c | 25 +-
src/backend/nodes/readfuncs.c | 15 +-
src/backend/optimizer/geqo/geqo_eval.c | 5 +-
src/backend/optimizer/geqo/geqo_pool.c | 17 +-
src/backend/optimizer/path/allpaths.c | 2 +-
src/backend/optimizer/path/costsize.c | 999 ++++++++++++++++++------------
src/backend/optimizer/path/indxpath.c | 12 +-
src/backend/optimizer/plan/createplan.c | 13 +-
src/backend/optimizer/plan/planagg.c | 7 +-
src/backend/optimizer/plan/planner.c | 26 +-
src/backend/optimizer/plan/subselect.c | 9 +-
src/backend/optimizer/prep/prepunion.c | 7 +-
src/backend/optimizer/util/appendinfo.c | 3 +-
src/backend/optimizer/util/clauses.c | 14 +-
src/backend/optimizer/util/pathnode.c | 268 ++++----
src/backend/optimizer/util/placeholder.c | 4 +-
src/backend/optimizer/util/plancat.c | 10 +-
src/backend/optimizer/util/relnode.c | 12 +-
src/backend/optimizer/util/restrictinfo.c | 3 +-
src/backend/utils/adt/selfuncs.c | 120 ++--
src/backend/utils/cache/plancache.c | 3 +-
src/include/nodes/nodes.h | 16 +-
src/include/optimizer/cost.h | 31 +-
src/include/utils/selfuncs.h | 5 +-
src/test/regress/regress.c | 5 +-
29 files changed, 1028 insertions(+), 687 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 62fb343..acc6ad4 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -24,6 +24,7 @@
#include "nodes/extensible.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
+#include "optimizer/cost.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
#include "storage/bufmgr.h"
@@ -61,6 +62,7 @@ static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
ExplainState *es);
static double elapsed_time(instr_time *starttime);
static bool ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used);
+static void explain_verbose_costs(Cost *cost, ExplainState *es);
static void ExplainNode(PlanState *planstate, List *ancestors,
const char *relationship, const char *plan_name,
ExplainState *es);
@@ -1041,6 +1043,26 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
return planstate_tree_walker(planstate, ExplainPreScanNode, rels_used);
}
+static void explain_verbose_costs(Cost *cost, ExplainState *es)
+{
+ ExplainPropertyFloat("cpu_index_tuple_cost", NULL,
+ cost->cpu_index_tuple_cost, 2, es);
+ ExplainPropertyFloat("cpu_operator_cost", NULL,
+ cost->cpu_operator_cost, 2, es);
+ ExplainPropertyFloat("cpu_tuple_cost", NULL,
+ cost->cpu_tuple_cost, 2, es);
+ ExplainPropertyFloat("parallel_setup_cost", NULL,
+ cost->parallel_setup_cost, 2, es);
+ ExplainPropertyFloat("parallel_tuple_cost", NULL,
+ cost->parallel_tuple_cost, 2, es);
+ ExplainPropertyFloat("random_page_cost", NULL,
+ cost->random_page_cost, 2, es);
+ ExplainPropertyFloat("seq_page_cost", NULL,
+ cost->seq_page_cost, 2, es);
+ ExplainPropertyFloat("disable_cost", NULL,
+ cost->disable_cost, 2, es);
+}
+
/*
* ExplainNode -
* Appends a description of a plan tree to es->str
@@ -1473,18 +1495,47 @@ ExplainNode(PlanState *planstate, List *ancestors,
if (es->costs)
{
- if (es->format == EXPLAIN_FORMAT_TEXT)
+ if (es->format == EXPLAIN_FORMAT_TEXT && !es->verbose)
{
appendStringInfo(es->str, " (cost=%.2f..%.2f rows=%.0f width=%d)",
- plan->startup_cost, plan->total_cost,
+ cost_asscalar(&plan->startup_cost),
+ cost_asscalar(&plan->total_cost),
plan->plan_rows, plan->plan_width);
- }
- else
- {
- ExplainPropertyFloat("Startup Cost", NULL, plan->startup_cost,
+ } else if (es->format == EXPLAIN_FORMAT_TEXT) { /* && es->verbose */
+ // XXX: other fields
+ appendStringInfo(es->str, " (cost=Seq page %.2f Rand page %2f CPU tuple: %2f CPU oper %2f"\
+ "..Seq page %.2f Rand page %2f CPU tuple: %2f CPU oper %2f"\
+ " rows=%.0f width=%d)",
+ plan->startup_cost.seq_page_cost,
+ plan->startup_cost.random_page_cost,
+ plan->startup_cost.cpu_tuple_cost,
+ plan->startup_cost.cpu_operator_cost,
+ plan->total_cost.seq_page_cost,
+ plan->total_cost.random_page_cost,
+ plan->total_cost.cpu_tuple_cost,
+ plan->total_cost.cpu_operator_cost,
+ plan->plan_rows, plan->plan_width);
+ } else if (!es->verbose) {
+ ExplainPropertyFloat("Startup Cost", NULL, cost_asscalar(&plan->startup_cost),
2, es);
- ExplainPropertyFloat("Total Cost", NULL, plan->total_cost,
+ ExplainPropertyFloat("Total Cost", NULL, cost_asscalar(&plan->total_cost),
2, es);
+
+ ExplainPropertyFloat("Plan Rows", NULL, plan->plan_rows,
+ 0, es);
+ ExplainPropertyInteger("Plan Width", NULL, plan->plan_width,
+ es);
+ }
+ else /* !EXPLAIN_FORMAT_TEXT text && es->verbose */
+ {
+ ExplainOpenGroup("Startup Cost", "Startup Cost", false, es);
+ explain_verbose_costs(&plan->startup_cost, es);
+ ExplainCloseGroup("Startup Cost", "Startup Cost", false, es);
+
+ ExplainOpenGroup("Total Cost", "Total Cost", true, es);
+ explain_verbose_costs(&plan->total_cost, es);
+ ExplainCloseGroup("Total Cost", "Total Cost", true, es);
+
ExplainPropertyFloat("Plan Rows", NULL, plan->plan_rows,
0, es);
ExplainPropertyInteger("Plan Width", NULL, plan->plan_width,
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index ec37558..797ee20 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -112,6 +112,7 @@
#include "executor/hashjoin.h"
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
+#include "optimizer/cost.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "utils/memutils.h"
@@ -256,7 +257,7 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel)
node->hj_FirstOuterTupleSlot = NULL;
}
else if (HJ_FILL_OUTER(node) ||
- (outerNode->plan->startup_cost < hashNode->ps.plan->total_cost &&
+ (cost_islt(&outerNode->plan->startup_cost, &hashNode->ps.plan->total_cost) &&
!node->hj_OuterNotEmpty))
{
node->hj_FirstOuterTupleSlot = ExecProcNode(outerNode);
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 2c364bd..6c41582 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -35,6 +35,7 @@
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
+#include "optimizer/cost.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@@ -1353,10 +1354,12 @@ ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent)
subplan1 = (SubPlan *) linitial(asplan->subplans);
subplan2 = (SubPlan *) lsecond(asplan->subplans);
- cost1 = subplan1->startup_cost + num_calls * subplan1->per_call_cost;
- cost2 = subplan2->startup_cost + num_calls * subplan2->per_call_cost;
+ cost1 = subplan1->startup_cost;
+ cost_add_mul(&cost1, &subplan1->per_call_cost, num_calls);
+ cost2 = subplan2->startup_cost;
+ cost_add_mul(&cost2, &subplan2->per_call_cost, num_calls);
- if (cost1 < cost2)
+ if (cost_islt(&cost1, &cost2))
asstate->active = 0;
else
asstate->active = 1;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 2fcd4a3..d262c16 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -32,6 +32,7 @@
#include "miscadmin.h"
#include "nodes/extensible.h"
#include "nodes/pathnodes.h"
+#include "optimizer/cost.h"
#include "utils/datum.h"
@@ -449,8 +450,10 @@ _equalSubPlan(const SubPlan *a, const SubPlan *b)
COMPARE_NODE_FIELD(setParam);
COMPARE_NODE_FIELD(parParam);
COMPARE_NODE_FIELD(args);
- COMPARE_SCALAR_FIELD(startup_cost);
- COMPARE_SCALAR_FIELD(per_call_cost);
+ if (cost_asscalar(&a->startup_cost) != cost_asscalar(&b->startup_cost))
+ return false;
+ if (cost_asscalar(&a->per_call_cost) != cost_asscalar(&b->per_call_cost))
+ return false;
return true;
}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index a80eccc..e605c10 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -34,6 +34,7 @@
#include "nodes/extensible.h"
#include "nodes/pathnodes.h"
#include "nodes/plannodes.h"
+#include "optimizer/cost.h"
#include "utils/datum.h"
#include "utils/rel.h"
@@ -86,6 +87,10 @@ static void outChar(StringInfo str, char c);
#define WRITE_FLOAT_FIELD(fldname,format) \
appendStringInfo(str, " :" CppAsString(fldname) " " format, node->fldname)
+/* Write a float field --- caller must give format to define precision */
+#define WRITE_COST_FIELD(fldname,format) \
+ appendStringInfo(str, " :" CppAsString(fldname) " " format, cost_asscalar(&node->fldname))
+
/* Write a boolean field */
#define WRITE_BOOL_FIELD(fldname) \
appendStringInfo(str, " :" CppAsString(fldname) " %s", \
@@ -327,8 +332,8 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
static void
_outPlanInfo(StringInfo str, const Plan *node)
{
- WRITE_FLOAT_FIELD(startup_cost, "%.2f");
- WRITE_FLOAT_FIELD(total_cost, "%.2f");
+ WRITE_COST_FIELD(startup_cost, "%.2f");
+ WRITE_COST_FIELD(total_cost, "%.2f");
WRITE_FLOAT_FIELD(plan_rows, "%.0f");
WRITE_INT_FIELD(plan_width);
WRITE_BOOL_FIELD(parallel_aware);
@@ -1321,8 +1326,8 @@ _outSubPlan(StringInfo str, const SubPlan *node)
WRITE_NODE_FIELD(setParam);
WRITE_NODE_FIELD(parParam);
WRITE_NODE_FIELD(args);
- WRITE_FLOAT_FIELD(startup_cost, "%.2f");
- WRITE_FLOAT_FIELD(per_call_cost, "%.2f");
+ WRITE_COST_FIELD(startup_cost, "%.2f");
+ WRITE_COST_FIELD(per_call_cost, "%.2f");
}
static void
@@ -1717,8 +1722,8 @@ _outPathInfo(StringInfo str, const Path *node)
WRITE_BOOL_FIELD(parallel_safe);
WRITE_INT_FIELD(parallel_workers);
WRITE_FLOAT_FIELD(rows, "%.0f");
- WRITE_FLOAT_FIELD(startup_cost, "%.2f");
- WRITE_FLOAT_FIELD(total_cost, "%.2f");
+ WRITE_COST_FIELD(startup_cost, "%.2f");
+ WRITE_COST_FIELD(total_cost, "%.2f");
WRITE_NODE_FIELD(pathkeys);
}
@@ -1757,7 +1762,7 @@ _outIndexPath(StringInfo str, const IndexPath *node)
WRITE_NODE_FIELD(indexorderbys);
WRITE_NODE_FIELD(indexorderbycols);
WRITE_ENUM_FIELD(indexscandir, ScanDirection);
- WRITE_FLOAT_FIELD(indextotalcost, "%.2f");
+ WRITE_COST_FIELD(indextotalcost, "%.2f");
WRITE_FLOAT_FIELD(indexselectivity, "%.4f");
}
@@ -2411,8 +2416,8 @@ _outPathTarget(StringInfo str, const PathTarget *node)
for (i = 0; i < list_length(node->exprs); i++)
appendStringInfo(str, " %u", node->sortgrouprefs[i]);
}
- WRITE_FLOAT_FIELD(cost.startup, "%.2f");
- WRITE_FLOAT_FIELD(cost.per_tuple, "%.2f");
+ WRITE_COST_FIELD(cost.startup, "%.2f");
+ WRITE_COST_FIELD(cost.per_tuple, "%.2f");
WRITE_INT_FIELD(width);
}
@@ -2537,7 +2542,7 @@ _outMinMaxAggInfo(StringInfo str, const MinMaxAggInfo *node)
WRITE_NODE_FIELD(target);
/* We intentionally omit subroot --- too large, not interesting enough */
WRITE_NODE_FIELD(path);
- WRITE_FLOAT_FIELD(pathcost, "%.2f");
+ WRITE_COST_FIELD(pathcost, "%.2f");
WRITE_NODE_FIELD(param);
}
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 764e3bb..701475c 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -38,6 +38,7 @@
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
#include "nodes/readfuncs.h"
+#include "optimizer/cost.h"
#include "utils/builtins.h"
@@ -113,6 +114,12 @@
token = pg_strtok(&length); /* get field value */ \
local_node->fldname = atof(token)
+/* Read a float field */
+#define READ_COST_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname.disable_cost = atof(token) // XXX
+
/* Read a boolean field */
#define READ_BOOL_FIELD(fldname) \
token = pg_strtok(&length); /* skip :fldname */ \
@@ -1534,8 +1541,8 @@ ReadCommonPlan(Plan *local_node)
{
READ_TEMP_LOCALS();
- READ_FLOAT_FIELD(startup_cost);
- READ_FLOAT_FIELD(total_cost);
+ READ_COST_FIELD(startup_cost);
+ READ_COST_FIELD(total_cost);
READ_FLOAT_FIELD(plan_rows);
READ_INT_FIELD(plan_width);
READ_BOOL_FIELD(parallel_aware);
@@ -2466,8 +2473,8 @@ _readSubPlan(void)
READ_NODE_FIELD(setParam);
READ_NODE_FIELD(parParam);
READ_NODE_FIELD(args);
- READ_FLOAT_FIELD(startup_cost);
- READ_FLOAT_FIELD(per_call_cost);
+ READ_COST_FIELD(startup_cost);
+ READ_COST_FIELD(per_call_cost);
READ_DONE();
}
diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c
index 7b67a29..9f827ba 100644
--- a/src/backend/optimizer/geqo/geqo_eval.c
+++ b/src/backend/optimizer/geqo/geqo_eval.c
@@ -29,6 +29,7 @@
#include "optimizer/joininfo.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
+#include "optimizer/cost.h"
#include "utils/memutils.h"
@@ -62,7 +63,7 @@ geqo_eval(PlannerInfo *root, Gene *tour, int num_gene)
Cost fitness;
int savelength;
struct HTAB *savehash;
-
+ extern double disable_cost;
/*
* Create a private memory context that will hold all temp storage
* allocated inside gimme_tree().
@@ -115,7 +116,7 @@ geqo_eval(PlannerInfo *root, Gene *tour, int num_gene)
fitness = best_path->total_cost;
}
else
- fitness = DBL_MAX;
+ cost_set_member(&fitness, disable_cost);
/*
* Restore join_rel_list to its former state, and put back original
diff --git a/src/backend/optimizer/geqo/geqo_pool.c b/src/backend/optimizer/geqo/geqo_pool.c
index f29fcc2..3ce7f8d 100644
--- a/src/backend/optimizer/geqo/geqo_pool.c
+++ b/src/backend/optimizer/geqo/geqo_pool.c
@@ -30,6 +30,7 @@
#include "optimizer/geqo_copy.h"
#include "optimizer/geqo_pool.h"
#include "optimizer/geqo_recombination.h"
+#include "optimizer/cost.h"
static int compare(const void *arg1, const void *arg2);
@@ -108,7 +109,7 @@ random_init_pool(PlannerInfo *root, Pool *pool)
init_tour(root, chromo[i].string, pool->string_length);
pool->data[i].worth = geqo_eval(root, chromo[i].string,
pool->string_length);
- if (pool->data[i].worth < DBL_MAX)
+ if (cost_asscalar(&pool->data[i].worth) < disable_cost)
i++;
else
{
@@ -147,9 +148,9 @@ compare(const void *arg1, const void *arg2)
const Chromosome *chromo1 = (const Chromosome *) arg1;
const Chromosome *chromo2 = (const Chromosome *) arg2;
- if (chromo1->worth == chromo2->worth)
+ if (cost_asscalar(&chromo1->worth) == cost_asscalar(&chromo2->worth))
return 0;
- else if (chromo1->worth > chromo2->worth)
+ else if (cost_isgt(&chromo1->worth, &chromo2->worth))
return 1;
else
return -1;
@@ -195,7 +196,7 @@ spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool)
tmp_chromo;
/* new chromo is so bad we can't use it */
- if (chromo->worth > pool->data[pool->size - 1].worth)
+ if (cost_isgt(&chromo->worth, &pool->data[pool->size - 1].worth))
return;
/* do a binary search to find the index of the new chromo */
@@ -209,11 +210,11 @@ spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool)
{
/* these 4 cases find a new location */
- if (chromo->worth <= pool->data[top].worth)
+ if (!cost_isgt(&chromo->worth, &pool->data[top].worth))
index = top;
- else if (chromo->worth == pool->data[mid].worth)
+ else if (cost_asscalar(&chromo->worth) == cost_asscalar(&pool->data[mid].worth))
index = mid;
- else if (chromo->worth == pool->data[bot].worth)
+ else if (cost_asscalar(&chromo->worth) == cost_asscalar(&pool->data[bot].worth))
index = bot;
else if (bot - top <= 1)
index = bot;
@@ -224,7 +225,7 @@ spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool)
* yet been found.
*/
- else if (chromo->worth < pool->data[mid].worth)
+ else if (cost_islt(&chromo->worth, &pool->data[mid].worth))
{
bot = mid;
mid = top + ((bot - top) / 2);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index db3a68a..d227eef 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1419,7 +1419,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
}
else if (nppath == NULL ||
(cheapest_partial_path != NULL &&
- cheapest_partial_path->total_cost < nppath->total_cost))
+ cost_islt(&cheapest_partial_path->total_cost, &nppath->total_cost)))
{
/* Partial path is cheaper or the only option. */
Assert(cheapest_partial_path != NULL);
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index c5f6593..1789f0b 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -117,7 +117,7 @@ double parallel_setup_cost = DEFAULT_PARALLEL_SETUP_COST;
int effective_cache_size = DEFAULT_EFFECTIVE_CACHE_SIZE;
-Cost disable_cost = 1.0e10;
+double disable_cost = 1.0e10;
int max_parallel_workers_per_gather = 2;
@@ -171,7 +171,7 @@ static Selectivity get_foreign_key_join_selectivity(PlannerInfo *root,
Relids inner_relids,
SpecialJoinInfo *sjinfo,
List **restrictlist);
-static Cost append_nonpartial_cost(List *subpaths, int numpaths,
+static Cost *append_nonpartial_cost(List *subpaths, int numpaths,
int parallel_workers);
static void set_rel_width(PlannerInfo *root, RelOptInfo *rel);
static double relation_byte_size(double tuples, int width);
@@ -211,7 +211,7 @@ void
cost_seqscan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, ParamPathInfo *param_info)
{
- Cost startup_cost = 0;
+ Cost startup_cost = {0};
Cost cpu_run_cost;
Cost disk_run_cost;
double spc_seq_page_cost;
@@ -229,7 +229,7 @@ cost_seqscan(Path *path, PlannerInfo *root,
path->rows = baserel->rows;
if (!enable_seqscan)
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
/* fetch estimated page cost for tablespace containing table */
get_tablespace_page_costs(baserel->reltablespace,
@@ -239,17 +239,18 @@ cost_seqscan(Path *path, PlannerInfo *root,
/*
* disk costs
*/
- disk_run_cost = spc_seq_page_cost * baserel->pages;
+ cost_set_member_mul_spc(&disk_run_cost, spc_, seq_page_cost, baserel->pages);
/* CPU costs */
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
- cpu_run_cost = cpu_per_tuple * baserel->tuples;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ cpu_run_cost = cpu_per_tuple;
+ cost_mul_scalar(&cpu_run_cost, baserel->tuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->pathtarget->cost.startup;
- cpu_run_cost += path->pathtarget->cost.per_tuple * path->rows;
+ cost_add(&startup_cost, &path->pathtarget->cost.startup);
+ cost_add_mul(&cpu_run_cost, &path->pathtarget->cost.per_tuple, path->rows);
/* Adjust costing for parallelism, if used. */
if (path->parallel_workers > 0)
@@ -257,7 +258,7 @@ cost_seqscan(Path *path, PlannerInfo *root,
double parallel_divisor = get_parallel_divisor(path);
/* The CPU cost is divided among all the workers. */
- cpu_run_cost /= parallel_divisor;
+ cost_mul_scalar(&cpu_run_cost, 1.0/parallel_divisor);
/*
* It may be possible to amortize some of the I/O cost, but probably
@@ -274,7 +275,7 @@ cost_seqscan(Path *path, PlannerInfo *root,
}
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + cpu_run_cost + disk_run_cost;
+ cost_set_sum3(&path->total_cost, &startup_cost, &cpu_run_cost, &disk_run_cost);
}
/*
@@ -288,14 +289,13 @@ void
cost_samplescan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, ParamPathInfo *param_info)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
RangeTblEntry *rte;
TableSampleClause *tsc;
TsmRoutine *tsm;
double spc_seq_page_cost,
- spc_random_page_cost,
- spc_page_cost;
+ spc_random_page_cost;
QualCost qpqual_cost;
Cost cpu_per_tuple;
@@ -319,14 +319,16 @@ cost_samplescan(Path *path, PlannerInfo *root,
&spc_seq_page_cost);
/* if NextSampleBlock is used, assume random access, else sequential */
- spc_page_cost = (tsm->NextSampleBlock != NULL) ?
- spc_random_page_cost : spc_seq_page_cost;
/*
* disk costs (recall that baserel->pages has already been set to the
* number of pages the sampling method will visit)
*/
- run_cost += spc_page_cost * baserel->pages;
+
+ if (tsm->NextSampleBlock != NULL)
+ cost_add_member_mul(&run_cost, random_page_cost, baserel->pages);
+ else
+ cost_add_member_mul(&run_cost, seq_page_cost, baserel->pages);
/*
* CPU costs (recall that baserel->tuples has already been set to the
@@ -338,15 +340,15 @@ cost_samplescan(Path *path, PlannerInfo *root,
*/
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
- run_cost += cpu_per_tuple * baserel->tuples;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ cost_add_mul(&run_cost, &cpu_per_tuple, baserel->tuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->pathtarget->cost.startup;
- run_cost += path->pathtarget->cost.per_tuple * path->rows;
+ cost_add(&startup_cost, &path->pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->pathtarget->cost.per_tuple, path->rows);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -364,8 +366,8 @@ cost_gather(GatherPath *path, PlannerInfo *root,
RelOptInfo *rel, ParamPathInfo *param_info,
double *rows)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
/* Mark the path with the correct row estimate */
if (rows)
@@ -377,14 +379,14 @@ cost_gather(GatherPath *path, PlannerInfo *root,
startup_cost = path->subpath->startup_cost;
- run_cost = path->subpath->total_cost - path->subpath->startup_cost;
+ cost_set_diff(&run_cost, &path->subpath->total_cost, &path->subpath->startup_cost);
/* Parallel setup and communication cost. */
- startup_cost += parallel_setup_cost;
- run_cost += parallel_tuple_cost * path->path.rows;
+ cost_add_member(&startup_cost, parallel_setup_cost);
+ cost_add_member_mul(&run_cost, parallel_tuple_cost, path->path.rows);
path->path.startup_cost = startup_cost;
- path->path.total_cost = (startup_cost + run_cost);
+ cost_set_sum2(&path->path.total_cost, &startup_cost, &run_cost);
}
/*
@@ -403,8 +405,8 @@ cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
Cost input_startup_cost, Cost input_total_cost,
double *rows)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
Cost comparison_cost;
double N;
double logN;
@@ -418,7 +420,7 @@ cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
path->path.rows = rel->rows;
if (!enable_gathermerge)
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
/*
* Add one to the number of workers to account for the leader. This might
@@ -430,16 +432,16 @@ cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
logN = LOG2(N);
/* Assumed cost per tuple comparison */
- comparison_cost = 2.0 * cpu_operator_cost;
+ cost_set_member_mul(&comparison_cost, cpu_operator_cost, 2.0);
/* Heap creation cost */
- startup_cost += comparison_cost * N * logN;
+ cost_add_mul(&startup_cost, &comparison_cost, N * logN);
/* Per-tuple heap maintenance cost */
- run_cost += path->path.rows * comparison_cost * logN;
+ cost_add_mul(&run_cost, &comparison_cost, path->path.rows * logN);
/* small cost for heap management, like cost_merge_append */
- run_cost += cpu_operator_cost * path->path.rows;
+ cost_add_member_mul(&run_cost, cpu_operator_cost, path->path.rows);
/*
* Parallel setup and communication cost. Since Gather Merge, unlike
@@ -447,11 +449,11 @@ cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
* worker, we bump the IPC cost up a little bit as compared with Gather.
* For lack of a better idea, charge an extra 5%.
*/
- startup_cost += parallel_setup_cost;
- run_cost += parallel_tuple_cost * path->path.rows * 1.05;
+ cost_add_member(&startup_cost, parallel_setup_cost);
+ cost_add_member_mul(&run_cost, parallel_tuple_cost, path->path.rows * 1.05);
- path->path.startup_cost = startup_cost + input_startup_cost;
- path->path.total_cost = (startup_cost + run_cost + input_total_cost);
+ cost_set_sum2(&path->path.startup_cost, &startup_cost, &input_startup_cost);
+ cost_set_sum3(&path->path.total_cost, &startup_cost, &run_cost, &input_total_cost);
}
/*
@@ -481,9 +483,9 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
bool indexonly = (path->path.pathtype == T_IndexOnlyScan);
amcostestimate_function amcostestimate;
List *qpquals;
- Cost startup_cost = 0;
- Cost run_cost = 0;
- Cost cpu_run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
+ Cost cpu_run_cost = {0};
Cost indexStartupCost;
Cost indexTotalCost;
Selectivity indexSelectivity;
@@ -531,7 +533,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
}
if (!enable_indexscan)
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
/* we don't need to check enable_indexonlyscan; indxpath.c does that */
/*
@@ -556,8 +558,9 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
path->indexselectivity = indexSelectivity;
/* all costs for touching index itself included here */
- startup_cost += indexStartupCost;
- run_cost += indexTotalCost - indexStartupCost;
+ cost_add(&startup_cost, &indexStartupCost);
+ cost_add(&run_cost, &indexTotalCost);
+ cost_sub(&run_cost, &indexStartupCost);
/* estimate number of main-table tuples fetched */
tuples_fetched = clamp_row_est(indexSelectivity * baserel->tuples);
@@ -614,7 +617,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
rand_heap_pages = pages_fetched;
- max_IO_cost = (pages_fetched * spc_random_page_cost) / loop_count;
+ cost_set_member_mul_spc(&max_IO_cost, spc_, random_page_cost, pages_fetched / loop_count);
/*
* In the perfectly correlated case, the number of pages touched by
@@ -636,7 +639,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
if (indexonly)
pages_fetched = ceil(pages_fetched * (1.0 - baserel->allvisfrac));
- min_IO_cost = (pages_fetched * spc_random_page_cost) / loop_count;
+ cost_set_member_mul_spc(&min_IO_cost, spc_, seq_page_cost, pages_fetched / loop_count);
}
else
{
@@ -655,7 +658,7 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
rand_heap_pages = pages_fetched;
/* max_IO_cost is for the perfectly uncorrelated case (csquared=0) */
- max_IO_cost = pages_fetched * spc_random_page_cost;
+ cost_set_member_mul_spc(&max_IO_cost, spc_, random_page_cost, pages_fetched);
/* min_IO_cost is for the perfectly correlated case (csquared=1) */
pages_fetched = ceil(indexSelectivity * (double) baserel->pages);
@@ -665,12 +668,12 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
if (pages_fetched > 0)
{
- min_IO_cost = spc_random_page_cost;
+ cost_set_member_mul_spc(&min_IO_cost, spc_, random_page_cost, 1.0);
if (pages_fetched > 1)
- min_IO_cost += (pages_fetched - 1) * spc_seq_page_cost;
+ cost_set_member_mul_spc(&min_IO_cost, spc_, seq_page_cost, pages_fetched - 1);
}
else
- min_IO_cost = 0;
+ cost_zero(&min_IO_cost);
}
if (partial_path)
@@ -711,7 +714,10 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
*/
csquared = indexCorrelation * indexCorrelation;
- run_cost += max_IO_cost + csquared * (min_IO_cost - max_IO_cost);
+ cost_add(&run_cost, &max_IO_cost);
+ cost_sub(&min_IO_cost, &max_IO_cost);
+ cost_mul_scalar(&min_IO_cost, csquared);
+ cost_add(&run_cost, &min_IO_cost);
/*
* Estimate CPU costs per tuple.
@@ -721,14 +727,14 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
*/
cost_qual_eval(&qpqual_cost, qpquals, root);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
- cpu_run_cost += cpu_per_tuple * tuples_fetched;
+ cost_add_mul(&cpu_run_cost, &cpu_per_tuple, tuples_fetched);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->path.pathtarget->cost.startup;
- cpu_run_cost += path->path.pathtarget->cost.per_tuple * path->path.rows;
+ cost_add(&startup_cost, &path->path.pathtarget->cost.startup);
+ cost_add_mul(&cpu_run_cost, &path->path.pathtarget->cost.per_tuple, path->path.rows);
/* Adjust costing for parallelism, if used. */
if (path->path.parallel_workers > 0)
@@ -738,13 +744,13 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
path->path.rows = clamp_row_est(path->path.rows / parallel_divisor);
/* The CPU cost is divided among all the workers. */
- cpu_run_cost /= parallel_divisor;
+ cost_mul_scalar(&cpu_run_cost, 1.0/parallel_divisor);
}
- run_cost += cpu_run_cost;
+ cost_add(&run_cost, &cpu_run_cost);
path->path.startup_cost = startup_cost;
- path->path.total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->path.total_cost, &startup_cost, &run_cost);
}
/*
@@ -941,8 +947,8 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
ParamPathInfo *param_info,
Path *bitmapqual, double loop_count)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
Cost indexTotalCost;
QualCost qpqual_cost;
Cost cpu_per_tuple;
@@ -966,13 +972,13 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
path->rows = baserel->rows;
if (!enable_bitmapscan)
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
pages_fetched = compute_bitmap_pages(root, baserel, bitmapqual,
loop_count, &indexTotalCost,
&tuples_fetched);
- startup_cost += indexTotalCost;
+ cost_add(&startup_cost, &indexTotalCost);
T = (baserel->pages > 1) ? (double) baserel->pages : 1.0;
/* Fetch estimated page costs for tablespace containing table. */
@@ -987,14 +993,15 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
* nonlinear, too. For lack of a better idea, interpolate like this to
* determine the cost per page.
*/
- if (pages_fetched >= 2.0)
- cost_per_page = spc_random_page_cost -
- (spc_random_page_cost - spc_seq_page_cost)
- * sqrt(pages_fetched / T);
- else
- cost_per_page = spc_random_page_cost;
+ if (pages_fetched >= 2.0) {
+ cost_set_member_mul_spc(&cost_per_page, spc_, random_page_cost,
+ 1-sqrt(pages_fetched/T));
+
+ cost_set_member_mul_spc(&cost_per_page, spc_, seq_page_cost, sqrt(pages_fetched/T));
+ } else
+ cost_set_member_mul_spc(&cost_per_page, spc_, random_page_cost, 1.0);
- run_cost += pages_fetched * cost_per_page;
+ cost_add_mul(&run_cost, &cost_per_page, pages_fetched);
/*
* Estimate CPU costs per tuple.
@@ -1007,9 +1014,9 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
*/
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
- cpu_run_cost = cpu_per_tuple * tuples_fetched;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ cost_add_mul(&cpu_run_cost, &cpu_per_tuple, tuples_fetched);
/* Adjust costing for parallelism, if used. */
if (path->parallel_workers > 0)
@@ -1017,20 +1024,20 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
double parallel_divisor = get_parallel_divisor(path);
/* The CPU cost is divided among all the workers. */
- cpu_run_cost /= parallel_divisor;
+ cost_mul_scalar(&cpu_run_cost, 1.0/parallel_divisor);
path->rows = clamp_row_est(path->rows / parallel_divisor);
}
- run_cost += cpu_run_cost;
+ cost_add(&run_cost, &cpu_run_cost);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->pathtarget->cost.startup;
- run_cost += path->pathtarget->cost.per_tuple * path->rows;
+ cost_add(&startup_cost, &path->pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->pathtarget->cost.per_tuple, path->rows);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -1051,7 +1058,7 @@ cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
* scan doesn't look to be the same cost as an indexscan to retrieve a
* single tuple.
*/
- *cost += 0.1 * cpu_operator_cost * path->rows;
+ cost_add_member_mul(cost, cpu_operator_cost, 0.1 * path->rows);
}
else if (IsA(path, BitmapAndPath))
{
@@ -1066,7 +1073,8 @@ cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
else
{
elog(ERROR, "unrecognized node type: %d", nodeTag(path));
- *cost = *selec = 0; /* keep compiler quiet */
+ *selec = 0; /* keep compiler quiet */
+ cost_zero(cost);
}
}
@@ -1083,7 +1091,7 @@ cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
void
cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
{
- Cost totalCost;
+ Cost totalCost = {0};
Selectivity selec;
ListCell *l;
@@ -1096,7 +1104,6 @@ cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
* cpu_operator_cost for each tbm_intersect needed. Probably too small,
* definitely too simplistic?
*/
- totalCost = 0.0;
selec = 1.0;
foreach(l, path->bitmapquals)
{
@@ -1108,9 +1115,9 @@ cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
selec *= subselec;
- totalCost += subCost;
+ cost_add(&totalCost, &subCost);
if (l != list_head(path->bitmapquals))
- totalCost += 100.0 * cpu_operator_cost;
+ cost_add_member_mul(&totalCost, cpu_operator_cost, 100.0);
}
path->bitmapselectivity = selec;
path->path.rows = 0; /* per above, not used */
@@ -1127,7 +1134,7 @@ cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
void
cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root)
{
- Cost totalCost;
+ Cost totalCost = {0};
Selectivity selec;
ListCell *l;
@@ -1141,7 +1148,6 @@ cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root)
* definitely too simplistic? We are aware that the tbm_unions are
* optimized out when the inputs are BitmapIndexScans.
*/
- totalCost = 0.0;
selec = 0.0;
foreach(l, path->bitmapquals)
{
@@ -1153,10 +1159,10 @@ cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root)
selec += subselec;
- totalCost += subCost;
+ cost_add(&totalCost, &subCost);
if (l != list_head(path->bitmapquals) &&
!IsA(subpath, IndexPath))
- totalCost += 100.0 * cpu_operator_cost;
+ cost_add_member_mul(&totalCost, cpu_operator_cost, 100.0);
}
path->bitmapselectivity = Min(selec, 1.0);
path->path.rows = 0; /* per above, not used */
@@ -1176,8 +1182,8 @@ void
cost_tidscan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, List *tidquals, ParamPathInfo *param_info)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
bool isCurrentOf = false;
QualCost qpqual_cost;
Cost cpu_per_tuple;
@@ -1234,11 +1240,12 @@ cost_tidscan(Path *path, PlannerInfo *root,
*/
if (isCurrentOf)
{
- Assert(baserel->baserestrictcost.startup >= disable_cost);
- startup_cost -= disable_cost;
+ // Assert(cost_asscalar(&baserel->baserestrictcost.startup) >= disable_cost);
+ Assert(&baserel->baserestrictcost.startup.disable_cost!=0);
+ cost_add_member_mul(&startup_cost, disable_cost, -1);
}
else if (!enable_tidscan)
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
/*
* The TID qual expressions will be computed once, any other baserestrict
@@ -1252,23 +1259,23 @@ cost_tidscan(Path *path, PlannerInfo *root,
NULL);
/* disk costs --- assume each tuple on a different page */
- run_cost += spc_random_page_cost * ntuples;
+ cost_add_member_mul_spc(&run_cost, spc_, random_page_cost, ntuples);
/* Add scanning CPU costs */
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
/* XXX currently we assume TID quals are a subset of qpquals */
- startup_cost += qpqual_cost.startup + tid_qual_cost.per_tuple;
- cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple -
- tid_qual_cost.per_tuple;
- run_cost += cpu_per_tuple * ntuples;
+ cost_add2(&startup_cost, &qpqual_cost.startup, &tid_qual_cost.per_tuple);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ cost_sub(&cpu_per_tuple, &tid_qual_cost.per_tuple);
+ cost_add_mul(&run_cost, &cpu_per_tuple, ntuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->pathtarget->cost.startup;
- run_cost += path->pathtarget->cost.per_tuple * path->rows;
+ cost_add(&startup_cost, &path->pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->pathtarget->cost.per_tuple, path->rows);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -1309,15 +1316,16 @@ cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root,
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
startup_cost = qpqual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
- run_cost = cpu_per_tuple * baserel->tuples;
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ run_cost = cpu_per_tuple;
+ cost_mul_scalar(&run_cost, baserel->tuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->path.pathtarget->cost.startup;
- run_cost += path->path.pathtarget->cost.per_tuple * path->path.rows;
+ cost_add(&startup_cost, &path->path.pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->path.pathtarget->cost.per_tuple, path->path.rows);
- path->path.startup_cost += startup_cost;
- path->path.total_cost += startup_cost + run_cost;
+ cost_add(&path->path.startup_cost, &startup_cost);
+ cost_add2(&path->path.total_cost, &startup_cost, &run_cost);
}
/*
@@ -1331,8 +1339,8 @@ void
cost_functionscan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, ParamPathInfo *param_info)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
QualCost qpqual_cost;
Cost cpu_per_tuple;
RangeTblEntry *rte;
@@ -1364,21 +1372,21 @@ cost_functionscan(Path *path, PlannerInfo *root,
*/
cost_qual_eval_node(&exprcost, (Node *) rte->functions, root);
- startup_cost += exprcost.startup + exprcost.per_tuple;
+ cost_add2(&startup_cost, &exprcost.startup, &exprcost.per_tuple);
/* Add scanning CPU costs */
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
- run_cost += cpu_per_tuple * baserel->tuples;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ cost_add_mul(&run_cost, &cpu_per_tuple, baserel->tuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->pathtarget->cost.startup;
- run_cost += path->pathtarget->cost.per_tuple * path->rows;
+ cost_add(&startup_cost, &path->pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->pathtarget->cost.per_tuple, path->rows);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -1392,8 +1400,8 @@ void
cost_tablefuncscan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, ParamPathInfo *param_info)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
QualCost qpqual_cost;
Cost cpu_per_tuple;
RangeTblEntry *rte;
@@ -1420,21 +1428,21 @@ cost_tablefuncscan(Path *path, PlannerInfo *root,
*/
cost_qual_eval_node(&exprcost, (Node *) rte->tablefunc, root);
- startup_cost += exprcost.startup + exprcost.per_tuple;
+ cost_add2(&startup_cost, &exprcost.startup, &exprcost.per_tuple);
/* Add scanning CPU costs */
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
- run_cost += cpu_per_tuple * baserel->tuples;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ cost_add_mul(&run_cost, &cpu_per_tuple, baserel->tuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->pathtarget->cost.startup;
- run_cost += path->pathtarget->cost.per_tuple * path->rows;
+ cost_add(&startup_cost, &path->pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->pathtarget->cost.per_tuple, path->rows);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -1448,8 +1456,8 @@ void
cost_valuesscan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, ParamPathInfo *param_info)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
QualCost qpqual_cost;
Cost cpu_per_tuple;
@@ -1467,21 +1475,22 @@ cost_valuesscan(Path *path, PlannerInfo *root,
* For now, estimate list evaluation cost at one operator eval per list
* (probably pretty bogus, but is it worth being smarter?)
*/
- cpu_per_tuple = cpu_operator_cost;
+ cost_set_member(&cpu_per_tuple, cpu_operator_cost);
/* Add scanning CPU costs */
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple += cpu_tuple_cost + qpqual_cost.per_tuple;
- run_cost += cpu_per_tuple * baserel->tuples;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_add_member(&cpu_per_tuple, cpu_tuple_cost);
+ cost_add(&cpu_per_tuple, &qpqual_cost.per_tuple);
+ cost_add_mul(&run_cost, &cpu_per_tuple, baserel->tuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->pathtarget->cost.startup;
- run_cost += path->pathtarget->cost.per_tuple * path->rows;
+ cost_add(&startup_cost, &path->pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->pathtarget->cost.per_tuple, path->rows);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -1498,8 +1507,8 @@ void
cost_ctescan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, ParamPathInfo *param_info)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
QualCost qpqual_cost;
Cost cpu_per_tuple;
@@ -1514,21 +1523,21 @@ cost_ctescan(Path *path, PlannerInfo *root,
path->rows = baserel->rows;
/* Charge one CPU tuple cost per row for tuplestore manipulation */
- cpu_per_tuple = cpu_tuple_cost;
+ cost_set_member(&cpu_per_tuple, cpu_tuple_cost);
/* Add scanning CPU costs */
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple += cpu_tuple_cost + qpqual_cost.per_tuple;
- run_cost += cpu_per_tuple * baserel->tuples;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ cost_add_mul(&run_cost, &cpu_per_tuple, baserel->tuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->pathtarget->cost.startup;
- run_cost += path->pathtarget->cost.per_tuple * path->rows;
+ cost_add(&startup_cost, &path->pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->pathtarget->cost.per_tuple, path->rows);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -1539,8 +1548,8 @@ void
cost_namedtuplestorescan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, ParamPathInfo *param_info)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
QualCost qpqual_cost;
Cost cpu_per_tuple;
@@ -1555,17 +1564,17 @@ cost_namedtuplestorescan(Path *path, PlannerInfo *root,
path->rows = baserel->rows;
/* Charge one CPU tuple cost per row for tuplestore manipulation */
- cpu_per_tuple = cpu_tuple_cost;
+ cost_set_member(&cpu_per_tuple, cpu_tuple_cost);
/* Add scanning CPU costs */
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple += cpu_tuple_cost + qpqual_cost.per_tuple;
- run_cost += cpu_per_tuple * baserel->tuples;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ cost_add_mul(&run_cost, &cpu_per_tuple, baserel->tuples);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -1576,8 +1585,8 @@ void
cost_resultscan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, ParamPathInfo *param_info)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
QualCost qpqual_cost;
Cost cpu_per_tuple;
@@ -1594,12 +1603,12 @@ cost_resultscan(Path *path, PlannerInfo *root,
/* We charge qual cost plus cpu_tuple_cost */
get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost);
- startup_cost += qpqual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
- run_cost += cpu_per_tuple * baserel->tuples;
+ cost_add(&startup_cost, &qpqual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qpqual_cost.per_tuple);
+ cost_add_mul(&run_cost, &cpu_per_tuple, baserel->tuples);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -1627,7 +1636,7 @@ cost_recursive_union(Path *runion, Path *nrterm, Path *rterm)
* size of each one of them. These are mighty shaky assumptions but it's
* hard to see how to do better.
*/
- total_cost += 10 * rterm->total_cost;
+ cost_add_mul(&total_cost, &rterm->total_cost, 10);
total_rows += 10 * rterm->rows;
/*
@@ -1635,7 +1644,7 @@ cost_recursive_union(Path *runion, Path *nrterm, Path *rterm)
* manipulating the tuplestores. (We don't worry about possible
* spill-to-disk costs.)
*/
- total_cost += cpu_tuple_cost * total_rows;
+ cost_add_member_mul(&total_cost, cpu_tuple_cost, total_rows);
runion->startup_cost = startup_cost;
runion->total_cost = total_cost;
@@ -1691,19 +1700,19 @@ cost_recursive_union(Path *runion, Path *nrterm, Path *rterm)
*/
void
cost_sort(Path *path, PlannerInfo *root,
- List *pathkeys, Cost input_cost, double tuples, int width,
- Cost comparison_cost, int sort_mem,
+ List *pathkeys, Cost *input_cost, double tuples, int width,
+ Cost *comparison_cost, int sort_mem,
double limit_tuples)
{
- Cost startup_cost = input_cost;
- Cost run_cost = 0;
+ Cost startup_cost = *input_cost;
+ Cost run_cost = {0};
double input_bytes = relation_byte_size(tuples, width);
double output_bytes;
double output_tuples;
long sort_mem_bytes = sort_mem * 1024L;
if (!enable_sort)
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
path->rows = tuples;
@@ -1715,7 +1724,7 @@ cost_sort(Path *path, PlannerInfo *root,
tuples = 2.0;
/* Include the default cost-per-comparison */
- comparison_cost += 2.0 * cpu_operator_cost;
+ cost_add_member_mul(comparison_cost, cpu_operator_cost, 2.0);
/* Do we have a useful LIMIT? */
if (limit_tuples > 0 && limit_tuples < tuples)
@@ -1745,7 +1754,7 @@ cost_sort(Path *path, PlannerInfo *root,
*
* Assume about N log2 N comparisons
*/
- startup_cost += comparison_cost * tuples * LOG2(tuples);
+ cost_add_mul(&startup_cost, comparison_cost, tuples * LOG2(tuples));
/* Disk costs */
@@ -1756,8 +1765,8 @@ cost_sort(Path *path, PlannerInfo *root,
log_runs = 1.0;
npageaccesses = 2.0 * npages * log_runs;
/* Assume 3/4ths of accesses are sequential, 1/4th are not */
- startup_cost += npageaccesses *
- (seq_page_cost * 0.75 + random_page_cost * 0.25);
+ cost_add_member_mul(&startup_cost, seq_page_cost, npageaccesses * 0.75);
+ cost_add_member_mul(&startup_cost, random_page_cost, npageaccesses * 0.25);
}
else if (tuples > 2 * output_tuples || input_bytes > sort_mem_bytes)
{
@@ -1767,12 +1776,12 @@ cost_sort(Path *path, PlannerInfo *root,
* factor is a bit higher than for quicksort. Tweak it so that the
* cost curve is continuous at the crossover point.
*/
- startup_cost += comparison_cost * tuples * LOG2(2.0 * output_tuples);
+ cost_add_mul(&startup_cost, comparison_cost, tuples * LOG2(2.0 * output_tuples));
}
else
{
/* We'll use plain quicksort on all the input tuples */
- startup_cost += comparison_cost * tuples * LOG2(tuples);
+ cost_add_mul(&startup_cost, comparison_cost, tuples * LOG2(tuples));
}
/*
@@ -1783,10 +1792,10 @@ cost_sort(Path *path, PlannerInfo *root,
* here --- the upper LIMIT will pro-rate the run cost so we'd be double
* counting the LIMIT otherwise.
*/
- run_cost += cpu_operator_cost * tuples;
+ cost_add_member_mul(&run_cost, cpu_operator_cost, tuples);
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -1795,7 +1804,7 @@ cost_sort(Path *path, PlannerInfo *root,
* The non-partial paths are assumed to be the first "numpaths" paths
* from the subpaths list, and to be in order of decreasing cost.
*/
-static Cost
+static Cost *
append_nonpartial_cost(List *subpaths, int numpaths, int parallel_workers)
{
Cost *costarr;
@@ -1808,7 +1817,7 @@ append_nonpartial_cost(List *subpaths, int numpaths, int parallel_workers)
int max_index;
if (numpaths == 0)
- return 0;
+ return NULL;
/*
* Array length is number of workers or number of relevant paths,
@@ -1847,12 +1856,12 @@ append_nonpartial_cost(List *subpaths, int numpaths, int parallel_workers)
if (path_index++ == numpaths)
break;
- costarr[min_index] += subpath->total_cost;
+ cost_add(&costarr[min_index], &subpath->total_cost);
/* Update the new min cost array index */
for (min_index = i = 0; i < arrlen; i++)
{
- if (costarr[i] < costarr[min_index])
+ if (cost_islt(&costarr[i], &costarr[min_index]))
min_index = i;
}
}
@@ -1860,11 +1869,11 @@ append_nonpartial_cost(List *subpaths, int numpaths, int parallel_workers)
/* Return the highest cost from the array */
for (max_index = i = 0; i < arrlen; i++)
{
- if (costarr[i] > costarr[max_index])
+ if (cost_isgt(&costarr[i], &costarr[max_index]))
max_index = i;
}
- return costarr[max_index];
+ return costarr+max_index;
}
/*
@@ -1876,8 +1885,8 @@ cost_append(AppendPath *apath)
{
ListCell *l;
- apath->path.startup_cost = 0;
- apath->path.total_cost = 0;
+ cost_zero(&apath->path.startup_cost);
+ cost_zero(&apath->path.total_cost);
apath->path.rows = 0;
if (apath->subpaths == NIL)
@@ -1903,7 +1912,7 @@ cost_append(AppendPath *apath)
Path *subpath = (Path *) lfirst(l);
apath->path.rows += subpath->rows;
- apath->path.total_cost += subpath->total_cost;
+ cost_add(&apath->path.total_cost, &subpath->total_cost);
}
}
else
@@ -1933,6 +1942,7 @@ cost_append(AppendPath *apath)
if (!pathkeys_contained_in(pathkeys, subpath->pathkeys))
{
+ Cost zerocost = {0};
/*
* We'll need to insert a Sort node, so include costs for
* that. We can use the parent's LIMIT if any, since we
@@ -1942,18 +1952,18 @@ cost_append(AppendPath *apath)
cost_sort(&sort_path,
NULL, /* doesn't currently need root */
pathkeys,
- subpath->total_cost,
+ &subpath->total_cost,
subpath->rows,
subpath->pathtarget->width,
- 0.0,
+ &zerocost,
work_mem,
apath->limit_tuples);
subpath = &sort_path;
}
apath->path.rows += subpath->rows;
- apath->path.startup_cost += subpath->startup_cost;
- apath->path.total_cost += subpath->total_cost;
+ cost_add(&apath->path.startup_cost, &subpath->startup_cost);
+ cost_add(&apath->path.total_cost, &subpath->total_cost);
}
}
}
@@ -1978,8 +1988,10 @@ cost_append(AppendPath *apath)
if (i == 0)
apath->path.startup_cost = subpath->startup_cost;
else if (i < apath->path.parallel_workers)
- apath->path.startup_cost = Min(apath->path.startup_cost,
- subpath->startup_cost);
+ apath->path.startup_cost = cost_islt(&apath->path.startup_cost,
+ &subpath->startup_cost) ?
+ apath->path.startup_cost :
+ subpath->startup_cost;
/*
* Apply parallel divisor to subpaths. Scale the number of rows
@@ -1997,7 +2009,7 @@ cost_append(AppendPath *apath)
subpath_parallel_divisor = get_parallel_divisor(subpath);
apath->path.rows += subpath->rows * (subpath_parallel_divisor /
parallel_divisor);
- apath->path.total_cost += subpath->total_cost;
+ cost_add(&apath->path.total_cost, &subpath->total_cost);
}
apath->path.rows = clamp_row_est(apath->path.rows);
@@ -2006,18 +2018,18 @@ cost_append(AppendPath *apath)
}
/* Add cost for non-partial subpaths. */
- apath->path.total_cost +=
+ cost_add(&apath->path.total_cost,
append_nonpartial_cost(apath->subpaths,
apath->first_partial_path,
- apath->path.parallel_workers);
+ apath->path.parallel_workers));
}
/*
* Although Append does not do any selection or projection, it's not free;
* add a small per-tuple overhead.
*/
- apath->path.total_cost +=
- cpu_tuple_cost * APPEND_CPU_COST_MULTIPLIER * apath->path.rows;
+ cost_add_member_mul(&apath->path.total_cost,
+ cpu_tuple_cost, APPEND_CPU_COST_MULTIPLIER * apath->path.rows);
}
/*
@@ -2050,8 +2062,8 @@ cost_merge_append(Path *path, PlannerInfo *root,
Cost input_startup_cost, Cost input_total_cost,
double tuples)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
Cost comparison_cost;
double N;
double logN;
@@ -2063,22 +2075,22 @@ cost_merge_append(Path *path, PlannerInfo *root,
logN = LOG2(N);
/* Assumed cost per tuple comparison */
- comparison_cost = 2.0 * cpu_operator_cost;
+ cost_add_member_mul(&comparison_cost, cpu_operator_cost, 2.0);
/* Heap creation cost */
- startup_cost += comparison_cost * N * logN;
+ cost_add_mul(&startup_cost, &comparison_cost, N * logN);
/* Per-tuple heap maintenance cost */
- run_cost += tuples * comparison_cost * logN;
+ cost_add_mul(&run_cost, &comparison_cost, logN);
/*
* Although MergeAppend does not do any selection or projection, it's not
* free; add a small per-tuple overhead.
*/
- run_cost += cpu_tuple_cost * APPEND_CPU_COST_MULTIPLIER * tuples;
+ cost_add_member_mul(&run_cost, cpu_tuple_cost, APPEND_CPU_COST_MULTIPLIER * tuples);
- path->startup_cost = startup_cost + input_startup_cost;
- path->total_cost = startup_cost + run_cost + input_total_cost;
+ cost_set_sum2(&path->startup_cost, &startup_cost, &input_startup_cost);
+ cost_set_sum3(&path->total_cost, &startup_cost, &run_cost, &input_total_cost);
}
/*
@@ -2099,10 +2111,11 @@ cost_material(Path *path,
double tuples, int width)
{
Cost startup_cost = input_startup_cost;
- Cost run_cost = input_total_cost - input_startup_cost;
+ Cost run_cost;
double nbytes = relation_byte_size(tuples, width);
long work_mem_bytes = work_mem * 1024L;
+ cost_set_diff(&run_cost, &input_total_cost, &input_startup_cost);
path->rows = tuples;
/*
@@ -2117,7 +2130,7 @@ cost_material(Path *path,
* doesn't do qual-checking or projection, so it's got less overhead than
* most plan nodes.
*/
- run_cost += 2 * cpu_operator_cost * tuples;
+ cost_add_member_mul(&run_cost, cpu_operator_cost, 2 * tuples);
/*
* If we will spill to disk, charge at the rate of seq_page_cost per page.
@@ -2129,11 +2142,11 @@ cost_material(Path *path,
{
double npages = ceil(nbytes / BLCKSZ);
- run_cost += seq_page_cost * npages;
+ cost_add_member_mul(&run_cost, seq_page_cost, npages);
}
path->startup_cost = startup_cost;
- path->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->total_cost, &startup_cost, &run_cost);
}
/*
@@ -2152,7 +2165,7 @@ cost_agg(Path *path, PlannerInfo *root,
AggStrategy aggstrategy, const AggClauseCosts *aggcosts,
int numGroupCols, double numGroups,
List *quals,
- Cost input_startup_cost, Cost input_total_cost,
+ Cost *input_startup_cost, Cost *input_total_cost,
double input_tuples)
{
double output_tuples;
@@ -2192,47 +2205,48 @@ cost_agg(Path *path, PlannerInfo *root,
*/
if (aggstrategy == AGG_PLAIN)
{
- startup_cost = input_total_cost;
- startup_cost += aggcosts->transCost.startup;
- startup_cost += aggcosts->transCost.per_tuple * input_tuples;
- startup_cost += aggcosts->finalCost.startup;
- startup_cost += aggcosts->finalCost.per_tuple;
+ startup_cost = *input_total_cost;
+ cost_add(&startup_cost, &aggcosts->transCost.startup);
+ cost_add_mul(&startup_cost, &aggcosts->transCost.per_tuple, input_tuples);
+ cost_add(&startup_cost, &aggcosts->finalCost.startup);
+ cost_add(&startup_cost, &aggcosts->finalCost.per_tuple);
/* we aren't grouping */
- total_cost = startup_cost + cpu_tuple_cost;
+ total_cost = startup_cost;
+ cost_add_member(&total_cost, cpu_tuple_cost);
output_tuples = 1;
}
else if (aggstrategy == AGG_SORTED || aggstrategy == AGG_MIXED)
{
/* Here we are able to deliver output on-the-fly */
- startup_cost = input_startup_cost;
- total_cost = input_total_cost;
+ startup_cost = *input_startup_cost;
+ total_cost = *input_total_cost;
if (aggstrategy == AGG_MIXED && !enable_hashagg)
{
- startup_cost += disable_cost;
- total_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
+ cost_add_member(&total_cost, disable_cost);
}
/* calcs phrased this way to match HASHED case, see note above */
- total_cost += aggcosts->transCost.startup;
- total_cost += aggcosts->transCost.per_tuple * input_tuples;
- total_cost += (cpu_operator_cost * numGroupCols) * input_tuples;
- total_cost += aggcosts->finalCost.startup;
- total_cost += aggcosts->finalCost.per_tuple * numGroups;
- total_cost += cpu_tuple_cost * numGroups;
+ cost_add(&total_cost, &aggcosts->transCost.startup);
+ cost_add_mul(&total_cost, &aggcosts->transCost.per_tuple, input_tuples);
+ cost_add_member_mul(&total_cost, cpu_operator_cost, numGroupCols * input_tuples);
+ cost_add(&total_cost, &aggcosts->finalCost.startup);
+ cost_add_mul(&total_cost, &aggcosts->finalCost.per_tuple, numGroups);
+ cost_add_member_mul(&total_cost, cpu_tuple_cost, numGroups);
output_tuples = numGroups;
}
else
{
/* must be AGG_HASHED */
- startup_cost = input_total_cost;
+ startup_cost = *input_total_cost;
if (!enable_hashagg)
- startup_cost += disable_cost;
- startup_cost += aggcosts->transCost.startup;
- startup_cost += aggcosts->transCost.per_tuple * input_tuples;
- startup_cost += (cpu_operator_cost * numGroupCols) * input_tuples;
- startup_cost += aggcosts->finalCost.startup;
+ cost_add_member(&startup_cost, disable_cost);
+ cost_add(&startup_cost, &aggcosts->transCost.startup);
+ cost_add_mul(&startup_cost, &aggcosts->transCost.per_tuple, input_tuples);
+ cost_add_member_mul(&startup_cost, cpu_operator_cost, numGroupCols * input_tuples);
+ cost_add(&startup_cost, &aggcosts->finalCost.startup);
total_cost = startup_cost;
- total_cost += aggcosts->finalCost.per_tuple * numGroups;
- total_cost += cpu_tuple_cost * numGroups;
+ cost_add_mul(&total_cost, &aggcosts->finalCost.per_tuple, numGroups);
+ cost_add_member_mul(&total_cost, cpu_tuple_cost, numGroups);
output_tuples = numGroups;
}
@@ -2245,8 +2259,9 @@ cost_agg(Path *path, PlannerInfo *root,
QualCost qual_cost;
cost_qual_eval(&qual_cost, quals, root);
- startup_cost += qual_cost.startup;
- total_cost += qual_cost.startup + output_tuples * qual_cost.per_tuple;
+ cost_add(&startup_cost, &qual_cost.startup);
+ cost_add(&total_cost, &qual_cost.startup);
+ cost_add_mul(&total_cost, &qual_cost.per_tuple, output_tuples);
output_tuples = clamp_row_est(output_tuples *
clauselist_selectivity(root,
@@ -2296,26 +2311,27 @@ cost_windowagg(Path *path, PlannerInfo *root,
Cost wfunccost;
QualCost argcosts;
- argcosts.startup = argcosts.per_tuple = 0;
+ cost_zero(&argcosts.startup);
+ cost_zero(&argcosts.per_tuple);
add_function_cost(root, wfunc->winfnoid, (Node *) wfunc,
&argcosts);
- startup_cost += argcosts.startup;
+ cost_add(&startup_cost, &argcosts.startup);
wfunccost = argcosts.per_tuple;
/* also add the input expressions' cost to per-input-row costs */
cost_qual_eval_node(&argcosts, (Node *) wfunc->args, root);
- startup_cost += argcosts.startup;
- wfunccost += argcosts.per_tuple;
+ cost_add(&startup_cost, &argcosts.startup);
+ cost_add(&wfunccost, &argcosts.per_tuple);
/*
* Add the filter's cost to per-input-row costs. XXX We should reduce
* input expression costs according to filter selectivity.
*/
cost_qual_eval_node(&argcosts, (Node *) wfunc->aggfilter, root);
- startup_cost += argcosts.startup;
- wfunccost += argcosts.per_tuple;
+ cost_add(&startup_cost, &argcosts.startup);
+ cost_add(&wfunccost, &argcosts.per_tuple);
- total_cost += wfunccost * input_tuples;
+ cost_add_mul(&total_cost, &wfunccost, input_tuples);
}
/*
@@ -2326,8 +2342,8 @@ cost_windowagg(Path *path, PlannerInfo *root,
* XXX this neglects costs of spooling the data to disk when it overflows
* work_mem. Sooner or later that should get accounted for.
*/
- total_cost += cpu_operator_cost * (numPartCols + numOrderCols) * input_tuples;
- total_cost += cpu_tuple_cost * input_tuples;
+ cost_add_member_mul(&total_cost, cpu_operator_cost, (numPartCols + numOrderCols) * input_tuples);
+ cost_add_member_mul(&total_cost, cpu_tuple_cost, input_tuples);
path->rows = input_tuples;
path->startup_cost = startup_cost;
@@ -2361,7 +2377,7 @@ cost_group(Path *path, PlannerInfo *root,
* Charge one cpu_operator_cost per comparison per input tuple. We assume
* all columns get compared at most of the tuples.
*/
- total_cost += cpu_operator_cost * input_tuples * numGroupCols;
+ cost_add_member_mul(&total_cost, cpu_operator_cost, input_tuples * numGroupCols);
/*
* If there are quals (HAVING quals), account for their cost and
@@ -2372,8 +2388,9 @@ cost_group(Path *path, PlannerInfo *root,
QualCost qual_cost;
cost_qual_eval(&qual_cost, quals, root);
- startup_cost += qual_cost.startup;
- total_cost += qual_cost.startup + output_tuples * qual_cost.per_tuple;
+ cost_add(&startup_cost, &qual_cost.startup);;
+ cost_add(&total_cost, &qual_cost.startup);
+ cost_add_mul(&total_cost, &qual_cost.per_tuple, output_tuples);
output_tuples = clamp_row_est(output_tuples *
clauselist_selectivity(root,
@@ -2418,8 +2435,8 @@ initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace,
Path *outer_path, Path *inner_path,
JoinPathExtraData *extra)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
double outer_path_rows = outer_path->rows;
Cost inner_rescan_start_cost;
Cost inner_rescan_total_cost;
@@ -2439,13 +2456,14 @@ initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace,
* their sum. We'll also pay the inner path's rescan startup cost
* multiple times.
*/
- startup_cost += outer_path->startup_cost + inner_path->startup_cost;
- run_cost += outer_path->total_cost - outer_path->startup_cost;
+ cost_add2(&startup_cost, &outer_path->startup_cost, &inner_path->startup_cost);
+ cost_add(&run_cost, &outer_path->total_cost);
+ cost_sub(&run_cost, &outer_path->startup_cost);
if (outer_path_rows > 1)
- run_cost += (outer_path_rows - 1) * inner_rescan_start_cost;
+ cost_add_mul(&run_cost, &inner_rescan_start_cost, outer_path_rows - 1);
- inner_run_cost = inner_path->total_cost - inner_path->startup_cost;
- inner_rescan_run_cost = inner_rescan_total_cost - inner_rescan_start_cost;
+ cost_set_diff(&inner_run_cost, &inner_path->total_cost, &inner_path->startup_cost);
+ cost_set_diff(&inner_rescan_run_cost, &inner_rescan_total_cost, &inner_rescan_start_cost);
if (jointype == JOIN_SEMI || jointype == JOIN_ANTI ||
extra->inner_unique)
@@ -2465,16 +2483,16 @@ initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace,
else
{
/* Normal case; we'll scan whole input rel for each outer row */
- run_cost += inner_run_cost;
+ cost_add(&run_cost, &inner_run_cost);
if (outer_path_rows > 1)
- run_cost += (outer_path_rows - 1) * inner_rescan_run_cost;
+ cost_add_mul(&run_cost, &inner_rescan_run_cost, outer_path_rows - 1);
}
/* CPU costs left for later */
/* Public result fields */
workspace->startup_cost = startup_cost;
- workspace->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&workspace->total_cost, &startup_cost, &run_cost);
/* Save private data for final_cost_nestloop */
workspace->run_cost = run_cost;
}
@@ -2529,7 +2547,7 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
* disabled, which doesn't seem like the way to bet.
*/
if (!enable_nestloop)
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
/* cost of inner-relation source data (we already dealt with outer rel) */
@@ -2590,9 +2608,9 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
* case, use inner_run_cost for the first matched tuple and
* inner_rescan_run_cost for additional ones.
*/
- run_cost += inner_run_cost * inner_scan_frac;
+ cost_add_mul(&run_cost, &inner_run_cost, inner_scan_frac);
if (outer_matched_rows > 1)
- run_cost += (outer_matched_rows - 1) * inner_rescan_run_cost * inner_scan_frac;
+ cost_add_mul(&run_cost, &inner_rescan_run_cost, (outer_matched_rows - 1) * inner_scan_frac);
/*
* Add the cost of inner-scan executions for unmatched outer rows.
@@ -2600,8 +2618,7 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
* of a nonempty scan. We consider that these are all rescans,
* since we used inner_run_cost once already.
*/
- run_cost += outer_unmatched_rows *
- inner_rescan_run_cost / inner_path_rows;
+ cost_add_mul(&run_cost, &inner_rescan_run_cost, outer_unmatched_rows / inner_path_rows);
/*
* We won't be evaluating any quals at all for unmatched rows, so
@@ -2627,7 +2644,7 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
ntuples += outer_unmatched_rows * inner_path_rows;
/* Now add the forced full scan, and decrement appropriate count */
- run_cost += inner_run_cost;
+ cost_add(&run_cost, &inner_run_cost);
if (outer_unmatched_rows >= 1)
outer_unmatched_rows -= 1;
else
@@ -2635,11 +2652,11 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
/* Add inner run cost for additional outer tuples having matches */
if (outer_matched_rows > 0)
- run_cost += outer_matched_rows * inner_rescan_run_cost * inner_scan_frac;
+ cost_add_mul(&run_cost, &inner_rescan_run_cost, outer_matched_rows * inner_scan_frac);
/* Add inner run cost for additional unmatched outer tuples */
if (outer_unmatched_rows > 0)
- run_cost += outer_unmatched_rows * inner_rescan_run_cost;
+ cost_add_mul(&run_cost, &inner_rescan_run_cost, outer_unmatched_rows);
}
}
else
@@ -2652,16 +2669,17 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
/* CPU costs */
cost_qual_eval(&restrict_qual_cost, path->joinrestrictinfo, root);
- startup_cost += restrict_qual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + restrict_qual_cost.per_tuple;
- run_cost += cpu_per_tuple * ntuples;
+ cost_add(&startup_cost, &restrict_qual_cost.startup);
+ cpu_per_tuple = restrict_qual_cost.per_tuple;
+ cost_add_member(&cpu_per_tuple, cpu_tuple_cost);
+ cost_add_mul(&run_cost, &cpu_per_tuple, ntuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->path.pathtarget->cost.startup;
- run_cost += path->path.pathtarget->cost.per_tuple * path->path.rows;
+ cost_add(&startup_cost, &path->path.pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->path.pathtarget->cost.per_tuple, path->path.rows);
path->path.startup_cost = startup_cost;
- path->path.total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->path.total_cost, &startup_cost, &run_cost);
}
/*
@@ -2702,8 +2720,9 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
List *outersortkeys, List *innersortkeys,
JoinPathExtraData *extra)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
+ Cost zerocost = {0};
double outer_path_rows = outer_path->rows;
double inner_path_rows = inner_path->rows;
Cost inner_run_cost;
@@ -2825,28 +2844,28 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
if (outersortkeys) /* do we need to sort outer? */
{
+ Cost tmp;
cost_sort(&sort_path,
root,
outersortkeys,
- outer_path->total_cost,
+ &outer_path->total_cost,
outer_path_rows,
outer_path->pathtarget->width,
- 0.0,
+ &zerocost,
work_mem,
-1.0);
- startup_cost += sort_path.startup_cost;
- startup_cost += (sort_path.total_cost - sort_path.startup_cost)
- * outerstartsel;
- run_cost += (sort_path.total_cost - sort_path.startup_cost)
- * (outerendsel - outerstartsel);
+ cost_add(&startup_cost, &sort_path.startup_cost);
+ cost_set_diff(&tmp, &sort_path.total_cost, &sort_path.startup_cost);
+ cost_add_mul(&startup_cost, &tmp, outerstartsel);
+ cost_add_mul(&run_cost, &tmp, outerendsel - outerstartsel);
}
else
{
- startup_cost += outer_path->startup_cost;
- startup_cost += (outer_path->total_cost - outer_path->startup_cost)
- * outerstartsel;
- run_cost += (outer_path->total_cost - outer_path->startup_cost)
- * (outerendsel - outerstartsel);
+ Cost tmp;
+ cost_add(&startup_cost, &outer_path->startup_cost);
+ cost_set_diff(&tmp, &outer_path->total_cost, &outer_path->startup_cost);
+ cost_add_mul(&startup_cost, &tmp, outerstartsel);
+ cost_add_mul(&run_cost, &tmp, outerendsel - outerstartsel);
}
if (innersortkeys) /* do we need to sort inner? */
@@ -2854,25 +2873,23 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
cost_sort(&sort_path,
root,
innersortkeys,
- inner_path->total_cost,
+ &inner_path->total_cost,
inner_path_rows,
inner_path->pathtarget->width,
- 0.0,
+ &zerocost,
work_mem,
-1.0);
- startup_cost += sort_path.startup_cost;
- startup_cost += (sort_path.total_cost - sort_path.startup_cost)
- * innerstartsel;
- inner_run_cost = (sort_path.total_cost - sort_path.startup_cost)
- * (innerendsel - innerstartsel);
+ cost_add(&startup_cost, &sort_path.startup_cost);
+ cost_set_diff(&inner_run_cost, &sort_path.total_cost, &sort_path.startup_cost);
+ cost_add_mul(&startup_cost, &inner_run_cost, innerstartsel);
+ cost_mul_scalar(&inner_run_cost, innerendsel - innerstartsel);
}
else
{
- startup_cost += inner_path->startup_cost;
- startup_cost += (inner_path->total_cost - inner_path->startup_cost)
- * innerstartsel;
- inner_run_cost = (inner_path->total_cost - inner_path->startup_cost)
- * (innerendsel - innerstartsel);
+ cost_add(&startup_cost, &inner_path->startup_cost);
+ cost_set_diff(&inner_run_cost, &inner_path->total_cost, &inner_path->startup_cost);
+ cost_add_mul(&startup_cost, &inner_run_cost, innerstartsel);
+ cost_mul_scalar(&inner_run_cost, innerendsel - innerstartsel);
}
/*
@@ -2887,7 +2904,7 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
/* Public result fields */
workspace->startup_cost = startup_cost;
- workspace->total_cost = startup_cost + run_cost + inner_run_cost;
+ cost_set_sum3(&workspace->total_cost, &startup_cost, &run_cost, &inner_run_cost);
/* Save private data for final_cost_mergejoin */
workspace->run_cost = run_cost;
workspace->inner_run_cost = inner_run_cost;
@@ -2975,7 +2992,7 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
* disabled, which doesn't seem like the way to bet.
*/
if (!enable_mergejoin)
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
/*
* Compute cost of the mergequals and qpquals (other restriction clauses)
@@ -2983,8 +3000,8 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
*/
cost_qual_eval(&merge_qual_cost, mergeclauses, root);
cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo, root);
- qp_qual_cost.startup -= merge_qual_cost.startup;
- qp_qual_cost.per_tuple -= merge_qual_cost.per_tuple;
+ cost_sub(&qp_qual_cost.startup, &merge_qual_cost.startup);
+ cost_sub(&qp_qual_cost.per_tuple, &merge_qual_cost.per_tuple);
/*
* With a SEMI or ANTI join, or if the innerrel is known unique, the
@@ -3059,7 +3076,8 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
* a more refined model. So we just need to inflate the inner run cost by
* rescanratio.
*/
- bare_inner_cost = inner_run_cost * rescanratio;
+ bare_inner_cost = inner_run_cost;
+ cost_mul_scalar(&bare_inner_cost, rescanratio);
/*
* When we interpose a Material node the re-fetch cost is assumed to be
@@ -3074,8 +3092,8 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
* Note: keep this estimate in sync with create_mergejoin_plan's labeling
* of the generated Material node.
*/
- mat_inner_cost = inner_run_cost +
- cpu_operator_cost * inner_rows * rescanratio;
+ mat_inner_cost = inner_run_cost;
+ cost_add_member_mul(&mat_inner_cost, cpu_operator_cost, inner_rows * rescanratio);
/*
* If we don't need mark/restore at all, we don't need materialization.
@@ -3087,7 +3105,7 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
* Prefer materializing if it looks cheaper, unless the user has asked to
* suppress materialization.
*/
- else if (enable_material && mat_inner_cost < bare_inner_cost)
+ else if (enable_material && cost_asscalar(&mat_inner_cost) < cost_asscalar(&bare_inner_cost))
path->materialize_inner = true;
/*
@@ -3131,9 +3149,9 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
/* Charge the right incremental cost for the chosen case */
if (path->materialize_inner)
- run_cost += mat_inner_cost;
+ cost_add(&run_cost, &mat_inner_cost);
else
- run_cost += bare_inner_cost;
+ cost_add(&run_cost, &bare_inner_cost);
/* CPU costs */
@@ -3142,12 +3160,12 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
* rows plus number of inner rows plus number of rescanned tuples (can we
* refine this?). At each one, we need to evaluate the mergejoin quals.
*/
- startup_cost += merge_qual_cost.startup;
- startup_cost += merge_qual_cost.per_tuple *
- (outer_skip_rows + inner_skip_rows * rescanratio);
- run_cost += merge_qual_cost.per_tuple *
+ cost_add(&startup_cost, &merge_qual_cost.startup);
+ cost_add_mul(&startup_cost, &merge_qual_cost.per_tuple,
+ outer_skip_rows + inner_skip_rows * rescanratio);
+ cost_add_mul(&run_cost, &merge_qual_cost.per_tuple,
((outer_rows - outer_skip_rows) +
- (inner_rows - inner_skip_rows) * rescanratio);
+ (inner_rows - inner_skip_rows) * rescanratio));
/*
* For each tuple that gets through the mergejoin proper, we charge
@@ -3158,16 +3176,16 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
* Note: we could adjust for SEMI/ANTI joins skipping some qual
* evaluations here, but it's probably not worth the trouble.
*/
- startup_cost += qp_qual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qp_qual_cost.per_tuple;
- run_cost += cpu_per_tuple * mergejointuples;
+ cost_add(&startup_cost, &qp_qual_cost.startup);
+ cost_set_member_add(&cpu_per_tuple, cpu_tuple_cost, &qp_qual_cost.per_tuple);
+ cost_add_mul(&run_cost, &cpu_per_tuple, mergejointuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->jpath.path.pathtarget->cost.startup;
- run_cost += path->jpath.path.pathtarget->cost.per_tuple * path->jpath.path.rows;
+ cost_add(&startup_cost, &path->jpath.path.pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->jpath.path.pathtarget->cost.per_tuple, path->jpath.path.rows);
path->jpath.path.startup_cost = startup_cost;
- path->jpath.path.total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->jpath.path.total_cost, &startup_cost, &run_cost);
}
/*
@@ -3260,8 +3278,8 @@ initial_cost_hashjoin(PlannerInfo *root, JoinCostWorkspace *workspace,
JoinPathExtraData *extra,
bool parallel_hash)
{
- Cost startup_cost = 0;
- Cost run_cost = 0;
+ Cost startup_cost = {0};
+ Cost run_cost = {0};
double outer_path_rows = outer_path->rows;
double inner_path_rows = inner_path->rows;
double inner_path_rows_total = inner_path_rows;
@@ -3272,9 +3290,10 @@ initial_cost_hashjoin(PlannerInfo *root, JoinCostWorkspace *workspace,
size_t space_allowed; /* unused */
/* cost of source data */
- startup_cost += outer_path->startup_cost;
- run_cost += outer_path->total_cost - outer_path->startup_cost;
- startup_cost += inner_path->total_cost;
+ cost_add(&startup_cost, &outer_path->startup_cost);
+ cost_add(&run_cost, &outer_path->total_cost);
+ cost_sub(&run_cost, &outer_path->startup_cost);
+ cost_add(&startup_cost, &inner_path->total_cost);
/*
* Cost of computing hash function: must do it once per input tuple. We
@@ -3286,9 +3305,9 @@ initial_cost_hashjoin(PlannerInfo *root, JoinCostWorkspace *workspace,
* should charge the extra eval costs of the left or right side, as
* appropriate, here. This seems more work than it's worth at the moment.
*/
- startup_cost += (cpu_operator_cost * num_hashclauses + cpu_tuple_cost)
- * inner_path_rows;
- run_cost += cpu_operator_cost * num_hashclauses * outer_path_rows;
+ cost_add_member_mul(&startup_cost, cpu_operator_cost, num_hashclauses * inner_path_rows);
+ cost_add_member_mul(&startup_cost, cpu_tuple_cost, inner_path_rows);
+ cost_add_member_mul(&run_cost, cpu_operator_cost, num_hashclauses * outer_path_rows);
/*
* If this is a parallel hash build, then the value we have for
@@ -3333,15 +3352,15 @@ initial_cost_hashjoin(PlannerInfo *root, JoinCostWorkspace *workspace,
double innerpages = page_size(inner_path_rows,
inner_path->pathtarget->width);
- startup_cost += seq_page_cost * innerpages;
- run_cost += seq_page_cost * (innerpages + 2 * outerpages);
+ cost_add_member_mul(&startup_cost, seq_page_cost, innerpages);
+ cost_add_member_mul(&run_cost, seq_page_cost, (innerpages + 2 * outerpages));
}
/* CPU costs left for later */
/* Public result fields */
workspace->startup_cost = startup_cost;
- workspace->total_cost = startup_cost + run_cost;
+ cost_set_sum2(&workspace->total_cost, &startup_cost, &run_cost);
/* Save private data for final_cost_hashjoin */
workspace->run_cost = run_cost;
workspace->numbuckets = numbuckets;
@@ -3405,7 +3424,7 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
* disabled, which doesn't seem like the way to bet.
*/
if (!enable_hashjoin)
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
/* mark the path with estimated # of batches */
path->num_batches = numbatches;
@@ -3503,7 +3522,7 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
if (relation_byte_size(clamp_row_est(inner_path_rows * innermcvfreq),
inner_path->pathtarget->width) >
(work_mem * 1024L))
- startup_cost += disable_cost;
+ cost_add_member(&startup_cost, disable_cost);
/*
* Compute cost of the hashquals and qpquals (other restriction clauses)
@@ -3511,8 +3530,8 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
*/
cost_qual_eval(&hash_qual_cost, hashclauses, root);
cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo, root);
- qp_qual_cost.startup -= hash_qual_cost.startup;
- qp_qual_cost.per_tuple -= hash_qual_cost.per_tuple;
+ cost_sub(&qp_qual_cost.startup, &hash_qual_cost.startup);
+ cost_sub(&qp_qual_cost.per_tuple, &hash_qual_cost.per_tuple);
/* CPU costs */
@@ -3538,9 +3557,9 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
outer_matched_rows = rint(outer_path_rows * extra->semifactors.outer_match_frac);
inner_scan_frac = 2.0 / (extra->semifactors.match_count + 1.0);
- startup_cost += hash_qual_cost.startup;
- run_cost += hash_qual_cost.per_tuple * outer_matched_rows *
- clamp_row_est(inner_path_rows * innerbucketsize * inner_scan_frac) * 0.5;
+ cost_add(&startup_cost, &hash_qual_cost.startup);
+ cost_add_mul(&run_cost, &hash_qual_cost.per_tuple, outer_matched_rows *
+ clamp_row_est(inner_path_rows * innerbucketsize * inner_scan_frac) * 0.5);
/*
* For unmatched outer-rel rows, the picture is quite a lot different.
@@ -3555,9 +3574,9 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
* effective cost per bucket entry is one-tenth what it is for
* matchable tuples.
*/
- run_cost += hash_qual_cost.per_tuple *
+ cost_add_mul(&run_cost, &hash_qual_cost.per_tuple,
(outer_path_rows - outer_matched_rows) *
- clamp_row_est(inner_path_rows / virtualbuckets) * 0.05;
+ clamp_row_est(inner_path_rows / virtualbuckets) * 0.05);
/* Get # of tuples that will pass the basic join */
if (path->jpath.jointype == JOIN_ANTI)
@@ -3577,9 +3596,9 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
* exactly. For lack of a better idea, halve the cost estimate to
* allow for that.
*/
- startup_cost += hash_qual_cost.startup;
- run_cost += hash_qual_cost.per_tuple * outer_path_rows *
- clamp_row_est(inner_path_rows * innerbucketsize) * 0.5;
+ cost_add(&startup_cost, &hash_qual_cost.startup);
+ cost_add_mul(&run_cost, &hash_qual_cost.per_tuple, outer_path_rows *
+ clamp_row_est(inner_path_rows * innerbucketsize) * 0.5);
/*
* Get approx # tuples passing the hashquals. We use
@@ -3595,16 +3614,17 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
* clauses that are to be applied at the join. (This is pessimistic since
* not all of the quals may get evaluated at each tuple.)
*/
- startup_cost += qp_qual_cost.startup;
- cpu_per_tuple = cpu_tuple_cost + qp_qual_cost.per_tuple;
- run_cost += cpu_per_tuple * hashjointuples;
+ cost_add(&startup_cost, &qp_qual_cost.startup);
+ cpu_per_tuple = qp_qual_cost.per_tuple;
+ cost_add_member(&cpu_per_tuple, cpu_tuple_cost);
+ cost_add_mul(&run_cost, &cpu_per_tuple, hashjointuples);
/* tlist eval costs are paid per output row, not per tuple scanned */
- startup_cost += path->jpath.path.pathtarget->cost.startup;
- run_cost += path->jpath.path.pathtarget->cost.per_tuple * path->jpath.path.rows;
+ cost_add(&startup_cost, &path->jpath.path.pathtarget->cost.startup);
+ cost_add_mul(&run_cost, &path->jpath.path.pathtarget->cost.per_tuple, path->jpath.path.rows);
path->jpath.path.startup_cost = startup_cost;
- path->jpath.path.total_cost = startup_cost + run_cost;
+ cost_set_sum2(&path->jpath.path.total_cost, &startup_cost, &run_cost);
}
@@ -3633,8 +3653,8 @@ cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan)
* cpu_operator_cost per tuple for the work of loading the hashtable,
* too.
*/
- sp_cost.startup += plan->total_cost +
- cpu_operator_cost * plan->plan_rows;
+ cost_add(&sp_cost.startup, &plan->total_cost);
+ cost_add_member_mul(&sp_cost.startup, cpu_operator_cost, plan->plan_rows);
/*
* The per-tuple costs include the cost of evaluating the lefthand
@@ -3654,25 +3674,26 @@ cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan)
* tuple_fraction estimates used by make_subplan() in
* plan/subselect.c.
*/
- Cost plan_run_cost = plan->total_cost - plan->startup_cost;
+ Cost plan_run_cost;
+ cost_set_diff(&plan_run_cost, &plan->total_cost, &plan->startup_cost);
if (subplan->subLinkType == EXISTS_SUBLINK)
{
/* we only need to fetch 1 tuple; clamp to avoid zero divide */
- sp_cost.per_tuple += plan_run_cost / clamp_row_est(plan->plan_rows);
+ cost_add_mul(&sp_cost.per_tuple, &plan_run_cost, clamp_row_est(plan->plan_rows));
}
else if (subplan->subLinkType == ALL_SUBLINK ||
subplan->subLinkType == ANY_SUBLINK)
{
/* assume we need 50% of the tuples */
- sp_cost.per_tuple += 0.50 * plan_run_cost;
+ cost_add_mul(&sp_cost.per_tuple, &plan_run_cost, 0.50);
/* also charge a cpu_operator_cost per row examined */
- sp_cost.per_tuple += 0.50 * plan->plan_rows * cpu_operator_cost;
+ cost_add_member_mul(&sp_cost.per_tuple, cpu_operator_cost, 0.50 * plan->plan_rows);
}
else
{
/* assume we need all tuples */
- sp_cost.per_tuple += plan_run_cost;
+ cost_add(&sp_cost.per_tuple, &plan_run_cost);
}
/*
@@ -3684,9 +3705,9 @@ cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan)
*/
if (subplan->parParam == NIL &&
ExecMaterializesOutput(nodeTag(plan)))
- sp_cost.startup += plan->startup_cost;
+ cost_add(&sp_cost.startup, &plan->startup_cost);
else
- sp_cost.per_tuple += plan->startup_cost;
+ cost_add(&sp_cost.per_tuple, &plan->startup_cost);
}
subplan->startup_cost = sp_cost.startup;
@@ -3724,8 +3745,8 @@ cost_rescan(PlannerInfo *root, Path *path,
* and isn't paid over again on rescans. However, all run costs
* will be paid over again.
*/
- *rescan_startup_cost = 0;
- *rescan_total_cost = path->total_cost - path->startup_cost;
+ cost_zero(rescan_startup_cost);
+ cost_set_diff(rescan_total_cost, &path->total_cost, &path->startup_cost);
break;
case T_HashJoin:
@@ -3736,8 +3757,8 @@ cost_rescan(PlannerInfo *root, Path *path,
if (((HashPath *) path)->num_batches == 1)
{
/* Startup cost is exactly the cost of hash table building */
- *rescan_startup_cost = 0;
- *rescan_total_cost = path->total_cost - path->startup_cost;
+ cost_zero(rescan_startup_cost);
+ cost_set_diff(rescan_total_cost, &path->total_cost, &path->startup_cost);
}
else
{
@@ -3755,19 +3776,20 @@ cost_rescan(PlannerInfo *root, Path *path,
* cpu_tuple_cost per tuple, unless the result is large enough
* to spill to disk.
*/
- Cost run_cost = cpu_tuple_cost * path->rows;
+ Cost run_cost;
double nbytes = relation_byte_size(path->rows,
path->pathtarget->width);
long work_mem_bytes = work_mem * 1024L;
+ cost_set_member_mul(&run_cost, cpu_tuple_cost, path->rows);
if (nbytes > work_mem_bytes)
{
/* It will spill, so account for re-read cost */
double npages = ceil(nbytes / BLCKSZ);
- run_cost += seq_page_cost * npages;
+ cost_add_member_mul(&run_cost, seq_page_cost, npages);
}
- *rescan_startup_cost = 0;
+ cost_zero(rescan_startup_cost);
*rescan_total_cost = run_cost;
}
break;
@@ -3782,19 +3804,20 @@ cost_rescan(PlannerInfo *root, Path *path,
* the run_cost charge in cost_sort, and also see comments in
* cost_material before you change it.)
*/
- Cost run_cost = cpu_operator_cost * path->rows;
+ Cost run_cost;
double nbytes = relation_byte_size(path->rows,
path->pathtarget->width);
long work_mem_bytes = work_mem * 1024L;
+ cost_set_member_mul(&run_cost, cpu_operator_cost, path->rows);
if (nbytes > work_mem_bytes)
{
/* It will spill, so account for re-read cost */
double npages = ceil(nbytes / BLCKSZ);
- run_cost += seq_page_cost * npages;
+ cost_add_member_mul(&run_cost, seq_page_cost, npages);
}
- *rescan_startup_cost = 0;
+ cost_zero(rescan_startup_cost);
*rescan_total_cost = run_cost;
}
break;
@@ -3822,8 +3845,8 @@ cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
ListCell *l;
context.root = root;
- context.total.startup = 0;
- context.total.per_tuple = 0;
+ cost_zero(&context.total.startup);
+ cost_zero(&context.total.per_tuple);
/* We don't charge any cost for the implicit ANDing at top level ... */
@@ -3847,8 +3870,8 @@ cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
cost_qual_eval_context context;
context.root = root;
- context.total.startup = 0;
- context.total.per_tuple = 0;
+ cost_zero(&context.total.startup);
+ cost_zero(&context.total.per_tuple);
cost_qual_eval_walker(qual, &context);
@@ -3871,13 +3894,13 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
{
RestrictInfo *rinfo = (RestrictInfo *) node;
- if (rinfo->eval_cost.startup < 0)
+ if (cost_asscalar(&rinfo->eval_cost.startup) < 0)
{
cost_qual_eval_context locContext;
locContext.root = context->root;
- locContext.total.startup = 0;
- locContext.total.per_tuple = 0;
+ cost_zero(&locContext.total.startup);
+ cost_zero(&locContext.total.per_tuple);
/*
* For an OR clause, recurse into the marked-up tree so that we
@@ -3895,13 +3918,13 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
if (rinfo->pseudoconstant)
{
/* count one execution during startup */
- locContext.total.startup += locContext.total.per_tuple;
- locContext.total.per_tuple = 0;
+ cost_add(&locContext.total.startup, &locContext.total.per_tuple);
+ cost_zero(&locContext.total.per_tuple);
}
rinfo->eval_cost = locContext.total;
}
- context->total.startup += rinfo->eval_cost.startup;
- context->total.per_tuple += rinfo->eval_cost.per_tuple;
+ cost_add(&context->total.startup, &rinfo->eval_cost.startup);
+ cost_add(&context->total.per_tuple, &rinfo->eval_cost.per_tuple);
/* do NOT recurse into children */
return false;
}
@@ -3953,12 +3976,13 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
QualCost sacosts;
set_sa_opfuncid(saop);
- sacosts.startup = sacosts.per_tuple = 0;
+ cost_zero(&sacosts.startup);
+ cost_zero(&sacosts.per_tuple);
add_function_cost(context->root, saop->opfuncid, NULL,
&sacosts);
- context->total.startup += sacosts.startup;
- context->total.per_tuple += sacosts.per_tuple *
- estimate_array_length(arraynode) * 0.5;
+ cost_add(&context->total.startup, &sacosts.startup);
+ cost_add_mul(&context->total.per_tuple, &sacosts.per_tuple,
+ estimate_array_length(arraynode) * 0.5);
}
else if (IsA(node, Aggref) ||
IsA(node, WindowFunc))
@@ -3999,10 +4023,10 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
cost_qual_eval_node(&perelemcost, (Node *) acoerce->elemexpr,
context->root);
- context->total.startup += perelemcost.startup;
- if (perelemcost.per_tuple > 0)
- context->total.per_tuple += perelemcost.per_tuple *
- estimate_array_length((Node *) acoerce->arg);
+ cost_add(&context->total.startup, &perelemcost.startup);
+ if (cost_asscalar(&perelemcost.per_tuple) > 0)
+ cost_add_mul(&context->total.per_tuple, &perelemcost.per_tuple,
+ estimate_array_length((Node *) acoerce->arg));
}
else if (IsA(node, RowCompareExpr))
{
@@ -4025,12 +4049,12 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
IsA(node, NextValueExpr))
{
/* Treat all these as having cost 1 */
- context->total.per_tuple += cpu_operator_cost;
+ cost_add_member(&context->total.per_tuple, cpu_operator_cost);
}
else if (IsA(node, CurrentOfExpr))
{
/* Report high cost to prevent selection of anything but TID scan */
- context->total.startup += disable_cost;
+ cost_add_member(&context->total.startup, disable_cost);
}
else if (IsA(node, SubLink))
{
@@ -4047,8 +4071,8 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
*/
SubPlan *subplan = (SubPlan *) node;
- context->total.startup += subplan->startup_cost;
- context->total.per_tuple += subplan->per_call_cost;
+ cost_add(&context->total.startup, &subplan->startup_cost);
+ cost_add(&context->total.per_tuple, &subplan->per_call_cost);
/*
* We don't want to recurse into the testexpr, because it was already
@@ -4111,8 +4135,8 @@ get_restriction_qual_cost(PlannerInfo *root, RelOptInfo *baserel,
/* Include costs of pushed-down clauses */
cost_qual_eval(qpqual_cost, param_info->ppi_clauses, root);
- qpqual_cost->startup += baserel->baserestrictcost.startup;
- qpqual_cost->per_tuple += baserel->baserestrictcost.per_tuple;
+ cost_add(&qpqual_cost->startup, &baserel->baserestrictcost.startup);
+ cost_add(&qpqual_cost->per_tuple, &baserel->baserestrictcost.per_tuple);
}
else
*qpqual_cost = baserel->baserestrictcost;
@@ -5223,8 +5247,8 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
ListCell *lc;
/* Vars are assumed to have cost zero, but other exprs do not */
- rel->reltarget->cost.startup = 0;
- rel->reltarget->cost.per_tuple = 0;
+ cost_zero(&rel->reltarget->cost.startup);
+ cost_zero(&rel->reltarget->cost.per_tuple);
foreach(lc, rel->reltarget->exprs)
{
@@ -5301,8 +5325,8 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
tuple_width += phinfo->ph_width;
cost_qual_eval_node(&cost, (Node *) phv->phexpr, root);
- rel->reltarget->cost.startup += cost.startup;
- rel->reltarget->cost.per_tuple += cost.per_tuple;
+ cost_add(&rel->reltarget->cost.startup, &cost.startup);
+ cost_add(&rel->reltarget->cost.per_tuple, &cost.per_tuple);
}
else
{
@@ -5319,8 +5343,8 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
tuple_width += item_width;
/* Not entirely clear if we need to account for cost, but do so */
cost_qual_eval_node(&cost, node, root);
- rel->reltarget->cost.startup += cost.startup;
- rel->reltarget->cost.per_tuple += cost.per_tuple;
+ cost_add(&rel->reltarget->cost.startup, &cost.startup);
+ cost_add(&rel->reltarget->cost.per_tuple, &cost.per_tuple);
}
}
@@ -5379,8 +5403,8 @@ set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
ListCell *lc;
/* Vars are assumed to have cost zero, but other exprs do not */
- target->cost.startup = 0;
- target->cost.per_tuple = 0;
+ cost_zero(&target->cost.startup);
+ cost_zero(&target->cost.per_tuple);
foreach(lc, target->exprs)
{
@@ -5434,8 +5458,8 @@ set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
/* Account for cost, too */
cost_qual_eval_node(&cost, node, root);
- target->cost.startup += cost.startup;
- target->cost.per_tuple += cost.per_tuple;
+ cost_add(&target->cost.startup, &cost.startup);
+ cost_add(&target->cost.per_tuple, &cost.per_tuple);
}
}
@@ -5603,3 +5627,178 @@ compute_bitmap_pages(PlannerInfo *root, RelOptInfo *baserel, Path *bitmapqual,
return pages_fetched;
}
+
+void cost_zero(Cost *to)
+{
+ memset(to, 0, sizeof(*to));
+}
+
+void cost_set_sum2(Cost *to, const Cost *from1, const Cost *from2)
+{
+ to->cpu_index_tuple_cost = from1->cpu_index_tuple_cost + from2 ->cpu_index_tuple_cost;
+ to->cpu_operator_cost = from1->cpu_operator_cost + from2->cpu_operator_cost;
+ to->cpu_tuple_cost = from1->cpu_tuple_cost + from2->cpu_tuple_cost;
+ to->parallel_setup_cost = from1->parallel_setup_cost + from2->parallel_setup_cost;
+ to->parallel_tuple_cost = from1->parallel_tuple_cost + from2->parallel_tuple_cost;
+ to->random_page_cost = from1->random_page_cost + from2->random_page_cost;
+ to->seq_page_cost = from1->seq_page_cost + from2->seq_page_cost;
+ to->disable_cost = from1->disable_cost + from2->disable_cost;
+}
+
+void cost_set_sum3(Cost *to, const Cost *from1, const Cost *from2, const Cost *from3)
+{
+ to->cpu_index_tuple_cost =
+ from1->cpu_index_tuple_cost +
+ from2->cpu_index_tuple_cost +
+ from3->cpu_index_tuple_cost;
+ to->cpu_operator_cost =
+ from1->cpu_operator_cost +
+ from2->cpu_operator_cost +
+ from3->cpu_operator_cost;
+ to->cpu_tuple_cost =
+ from1->cpu_tuple_cost +
+ from2->cpu_tuple_cost +
+ from3->cpu_tuple_cost;
+ to->parallel_setup_cost =
+ from1->parallel_setup_cost +
+ from2->parallel_setup_cost +
+ from3->parallel_setup_cost;
+ to->parallel_tuple_cost =
+ from1->parallel_tuple_cost +
+ from2->parallel_tuple_cost +
+ from3->parallel_tuple_cost;
+ to->random_page_cost =
+ from1->random_page_cost +
+ from2->random_page_cost +
+ from3->random_page_cost;
+ to->seq_page_cost =
+ from1->seq_page_cost +
+ from2->seq_page_cost +
+ from3->seq_page_cost;
+ to->disable_cost =
+ from1->disable_cost +
+ from2->disable_cost +
+ from3->disable_cost;
+}
+
+void cost_set_diff(Cost *to, const Cost *from1, const Cost *from2)
+{
+ to->cpu_index_tuple_cost = from1->cpu_index_tuple_cost - from2 ->cpu_index_tuple_cost;
+ to->cpu_operator_cost = from1->cpu_operator_cost - from2->cpu_operator_cost;
+ to->cpu_tuple_cost = from1->cpu_tuple_cost - from2->cpu_tuple_cost;
+ to->parallel_setup_cost = from1->parallel_setup_cost - from2->parallel_setup_cost;
+ to->parallel_tuple_cost = from1->parallel_tuple_cost - from2->parallel_tuple_cost;
+ to->random_page_cost = from1->random_page_cost - from2->random_page_cost;
+ to->seq_page_cost = from1->seq_page_cost - from2->seq_page_cost;
+ to->disable_cost = from1->disable_cost - from2->disable_cost;
+}
+
+void cost_add(Cost *to, const Cost *from1)
+{
+ /* Hack to allow calling append_nonpartial_cost... */
+ if (!from1)
+ return;
+
+ to->cpu_index_tuple_cost += from1->cpu_index_tuple_cost;
+ to->cpu_operator_cost += from1->cpu_operator_cost;
+ to->cpu_tuple_cost += from1->cpu_tuple_cost;
+ to->parallel_setup_cost += from1->parallel_setup_cost;
+ to->parallel_tuple_cost += from1->parallel_tuple_cost;
+ to->random_page_cost += from1->random_page_cost;
+ to->seq_page_cost += from1->seq_page_cost;
+ to->disable_cost += from1->disable_cost;
+}
+
+void cost_add2(Cost *to, const Cost *from1, const Cost *from2)
+{
+ to->cpu_index_tuple_cost +=
+ from1->cpu_index_tuple_cost +
+ from2->cpu_index_tuple_cost;
+ to->cpu_operator_cost +=
+ from1->cpu_operator_cost +
+ from2->cpu_operator_cost;
+ to->cpu_tuple_cost +=
+ from1->cpu_tuple_cost +
+ from2->cpu_tuple_cost;
+ to->parallel_setup_cost +=
+ from1->parallel_setup_cost +
+ from2->parallel_setup_cost;
+ to->parallel_tuple_cost +=
+ from1->parallel_tuple_cost +
+ from2->parallel_tuple_cost;
+ to->random_page_cost +=
+ from1->random_page_cost +
+ from2->random_page_cost;
+ to->seq_page_cost +=
+ from1->seq_page_cost +
+ from2->seq_page_cost;
+ to->disable_cost +=
+ from1->disable_cost +
+ from2->disable_cost;
+}
+
+void cost_add_mul(Cost *to, const Cost *from1, double mul)
+{
+ to->cpu_index_tuple_cost +=
+ mul * from1->cpu_index_tuple_cost;
+ to->cpu_operator_cost +=
+ mul * from1->cpu_operator_cost;
+ to->cpu_tuple_cost +=
+ mul * from1->cpu_tuple_cost;
+ to->parallel_setup_cost +=
+ mul * from1->parallel_setup_cost;
+ to->parallel_tuple_cost +=
+ mul * from1->parallel_tuple_cost;
+ to->random_page_cost +=
+ mul * from1->random_page_cost;
+ to->seq_page_cost +=
+ mul * from1->seq_page_cost;
+ to->disable_cost +=
+ mul * from1->disable_cost;
+}
+
+void cost_sub(Cost *to, const Cost *from1)
+{
+ to->cpu_index_tuple_cost -= from1->cpu_index_tuple_cost;
+ to->cpu_operator_cost -= from1->cpu_operator_cost;
+ to->cpu_tuple_cost -= from1->cpu_tuple_cost;
+ to->parallel_setup_cost -= from1->parallel_setup_cost;
+ to->parallel_tuple_cost -= from1->parallel_tuple_cost;
+ to->random_page_cost -= from1->random_page_cost;
+ to->seq_page_cost -= from1->seq_page_cost;
+ to->disable_cost -= from1->disable_cost;
+}
+
+void cost_mul_scalar(Cost *to, double mul)
+{
+ to->cpu_index_tuple_cost *= mul;
+ to->cpu_operator_cost *= mul;
+ to->cpu_tuple_cost *= mul;
+ to->parallel_setup_cost *= mul;
+ to->parallel_tuple_cost *= mul;
+ to->random_page_cost *= mul;
+ to->seq_page_cost *= mul;
+ to->disable_cost *= mul;
+}
+
+double cost_asscalar(const Cost *to)
+{
+ return to->cpu_index_tuple_cost
+ + to->cpu_operator_cost
+ + to->cpu_tuple_cost
+ + to->parallel_setup_cost
+ + to->parallel_tuple_cost
+ + to->random_page_cost
+ + to->seq_page_cost
+ + to->disable_cost;
+}
+
+bool cost_isgt(const Cost *to, const Cost *than)
+{
+ return cost_asscalar(to) > cost_asscalar(than);
+}
+
+bool cost_islt(const Cost *to, const Cost *than)
+{
+ return cost_asscalar(to) < cost_asscalar(than);
+}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 37b257c..1277dec 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1372,7 +1372,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
PathClauseUsage *pathinfo;
List *clauselist;
List *bestpaths = NIL;
- Cost bestcost = 0;
+ Cost bestcost = {0};
int i,
j;
ListCell *l;
@@ -1469,7 +1469,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
cost_bitmap_tree_node(pathinfo->path, &ncost, &nselec);
cost_bitmap_tree_node(pathinfoarray[i]->path, &ocost, &oselec);
- if (ncost < ocost)
+ if (cost_islt(&ncost, &ocost))
pathinfoarray[i] = pathinfo;
}
else
@@ -1537,7 +1537,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
/* tentatively add new path to paths, so we can estimate cost */
paths = lappend(paths, pathinfo->path);
newcost = bitmap_and_cost_est(root, rel, paths);
- if (newcost < costsofar)
+ if (cost_islt(&newcost, &costsofar))
{
/* keep new path in paths, update subsidiary variables */
costsofar = newcost;
@@ -1554,7 +1554,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
}
/* Keep the cheapest AND-group (or singleton) */
- if (i == 0 || costsofar < bestcost)
+ if (i == 0 || cost_islt(&costsofar, &bestcost))
{
bestpaths = paths;
bestcost = costsofar;
@@ -1586,9 +1586,9 @@ path_usage_comparator(const void *a, const void *b)
/*
* If costs are the same, sort by selectivity.
*/
- if (acost < bcost)
+ if (cost_islt(&acost, &bcost))
return -1;
- if (acost > bcost)
+ if (cost_isgt(&acost, &bcost))
return 1;
if (aselec < bselec)
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index aee81bd..561151d 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -3211,7 +3211,7 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
iscan->indexqual,
iscan->indexqualorig);
/* and set its cost/width fields appropriately */
- plan->startup_cost = 0.0;
+ cost_zero(&plan->startup_cost);
plan->total_cost = ipath->indextotalcost;
plan->plan_rows =
clamp_row_est(ipath->indexselectivity * ipath->path.parent->tuples);
@@ -4197,7 +4197,7 @@ create_mergejoin_plan(PlannerInfo *root,
* sync with final_cost_mergejoin.)
*/
copy_plan_costsize(matplan, inner_plan);
- matplan->total_cost += cpu_operator_cost * matplan->plan_rows;
+ cost_add_member_mul(&matplan->total_cost, cpu_operator_cost, matplan->plan_rows);
inner_plan = matplan;
}
@@ -4994,7 +4994,7 @@ order_qual_clauses(PlannerInfo *root, List *clauses)
* security level, which is not so great, but we can alleviate
* that risk by applying the cost limit cutoff.
*/
- if (rinfo->leakproof && items[i].cost < 10 * cpu_operator_cost)
+ if (rinfo->leakproof && cost_asscalar(&items[i].cost) < 10 * cpu_operator_cost)
items[i].security_level = 0;
else
items[i].security_level = rinfo->security_level;
@@ -5021,7 +5021,7 @@ order_qual_clauses(PlannerInfo *root, List *clauses)
if (newitem.security_level > olditem->security_level ||
(newitem.security_level == olditem->security_level &&
- newitem.cost >= olditem->cost))
+ !cost_islt(&newitem.cost, &olditem->cost)))
break;
items[j] = *olditem;
}
@@ -5083,12 +5083,13 @@ label_sort_with_costsize(PlannerInfo *root, Sort *plan, double limit_tuples)
{
Plan *lefttree = plan->plan.lefttree;
Path sort_path; /* dummy for result of cost_sort */
+ Cost zero = {0};
cost_sort(&sort_path, root, NIL,
- lefttree->total_cost,
+ &lefttree->total_cost,
lefttree->plan_rows,
lefttree->plan_width,
- 0.0,
+ &zero,
work_mem,
limit_tuples);
plan->plan.startup_cost = sort_path.startup_cost;
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index 974f620..0fd3897 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -314,7 +314,7 @@ find_minmax_aggs_walker(Node *node, List **context)
mminfo->target = curTarget->expr;
mminfo->subroot = NULL; /* don't compute path yet */
mminfo->path = NULL;
- mminfo->pathcost = 0;
+ cost_zero(&mminfo->pathcost);
mminfo->param = NULL;
*context = lappend(*context, mminfo);
@@ -484,8 +484,9 @@ build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo,
* Note: cost calculation here should match
* compare_fractional_path_costs().
*/
- path_cost = sorted_path->startup_cost +
- path_fraction * (sorted_path->total_cost - sorted_path->startup_cost);
+ cost_set_diff(&path_cost, &sorted_path->total_cost, &sorted_path->startup_cost);
+ cost_mul_scalar(&path_cost, path_fraction);
+ cost_add(&path_cost, &sorted_path->startup_cost);
/* Save state for further processing */
mminfo->subroot = subroot;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 7fe11b5..1280388 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -455,10 +455,11 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
* Ideally we'd use cost_gather here, but setting up dummy path data
* to satisfy it doesn't seem much cleaner than knowing what it does.
*/
- gather->plan.startup_cost = top_plan->startup_cost +
- parallel_setup_cost;
- gather->plan.total_cost = top_plan->total_cost +
- parallel_setup_cost + parallel_tuple_cost * top_plan->plan_rows;
+ cost_set_member_add(&gather->plan.startup_cost, parallel_setup_cost, &top_plan->startup_cost);
+
+ cost_set_member_mul(&gather->plan.total_cost, parallel_tuple_cost, top_plan->plan_rows);
+ cost_add_member(&gather->plan.total_cost, parallel_setup_cost);
+ cost_add(&gather->plan.total_cost, &top_plan->total_cost);
gather->plan.plan_rows = top_plan->plan_rows;
gather->plan.plan_width = top_plan->plan_width;
gather->plan.parallel_aware = false;
@@ -533,7 +534,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->jitFlags = PGJIT_NONE;
if (jit_enabled && jit_above_cost >= 0 &&
- top_plan->total_cost > jit_above_cost)
+ cost_asscalar(&top_plan->total_cost) > jit_above_cost)
{
result->jitFlags |= PGJIT_PERFORM;
@@ -541,10 +542,10 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
* Decide how much effort should be put into generating better code.
*/
if (jit_optimize_above_cost >= 0 &&
- top_plan->total_cost > jit_optimize_above_cost)
+ cost_asscalar(&top_plan->total_cost) > jit_optimize_above_cost)
result->jitFlags |= PGJIT_OPT3;
if (jit_inline_above_cost >= 0 &&
- top_plan->total_cost > jit_inline_above_cost)
+ cost_asscalar(&top_plan->total_cost) > jit_inline_above_cost)
result->jitFlags |= PGJIT_INLINE;
/*
@@ -5790,7 +5791,7 @@ make_sort_input_target(PlannerInfo *root,
* cpu_operator_cost". Note this will take in any PL function
* with default cost.
*/
- if (cost.per_tuple > 10 * cpu_operator_cost)
+ if (cost_asscalar(&cost.per_tuple) > 10 * cpu_operator_cost)
{
postpone_col[i] = true;
have_expensive = true;
@@ -6206,13 +6207,14 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
* expressions each time. (XXX that's pretty inefficient...)
*/
cost_qual_eval(&indexExprCost, indexInfo->indexprs, root);
- comparisonCost = 2.0 * (indexExprCost.startup + indexExprCost.per_tuple);
+ cost_set_sum2(&comparisonCost, &indexExprCost.startup, &indexExprCost.per_tuple);
+ cost_mul_scalar(&comparisonCost, 2);
/* Estimate the cost of seq scan + sort */
seqScanPath = create_seqscan_path(root, rel, NULL, 0);
cost_sort(&seqScanAndSortPath, root, NIL,
- seqScanPath->total_cost, rel->tuples, rel->reltarget->width,
- comparisonCost, maintenance_work_mem, -1.0);
+ &seqScanPath->total_cost, rel->tuples, rel->reltarget->width,
+ &comparisonCost, maintenance_work_mem, -1.0);
/* Estimate the cost of index scan */
indexScanPath = create_index_path(root, indexInfo,
@@ -6220,7 +6222,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
ForwardScanDirection, false,
NULL, 1.0, false);
- return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
+ return cost_islt(&seqScanAndSortPath.total_cost, &indexScanPath->path.total_cost);
}
/*
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 48b62a5..5780534 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -2060,7 +2060,7 @@ SS_identify_outer_params(PlannerInfo *root)
void
SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
{
- Cost initplan_cost;
+ Cost initplan_cost = {0};
ListCell *lc;
/* Nothing to do if no initPlans */
@@ -2073,12 +2073,11 @@ SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
* This is a conservative overestimate, since in fact an initPlan might be
* executed later than plan startup, or even not at all.
*/
- initplan_cost = 0;
foreach(lc, root->init_plans)
{
SubPlan *initsubplan = (SubPlan *) lfirst(lc);
- initplan_cost += initsubplan->startup_cost + initsubplan->per_call_cost;
+ cost_add2(&initplan_cost, &initsubplan->startup_cost, &initsubplan->per_call_cost);
}
/*
@@ -2088,8 +2087,8 @@ SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
{
Path *path = (Path *) lfirst(lc);
- path->startup_cost += initplan_cost;
- path->total_cost += initplan_cost;
+ cost_add(&path->startup_cost, &initplan_cost);
+ cost_add(&path->total_cost, &initplan_cost);
path->parallel_safe = false;
}
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index b01c9bb..a9bf448 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1025,6 +1025,7 @@ choose_hashed_setop(PlannerInfo *root, List *groupClauses,
Path hashed_p;
Path sorted_p;
double tuple_fraction;
+ Cost zerocost = {0};
/* Check whether the operators support sorting or hashing */
can_sort = grouping_is_sortable(groupClauses);
@@ -1071,7 +1072,7 @@ choose_hashed_setop(PlannerInfo *root, List *groupClauses,
cost_agg(&hashed_p, root, AGG_HASHED, NULL,
numGroupCols, dNumGroups,
NIL,
- input_path->startup_cost, input_path->total_cost,
+ &input_path->startup_cost, &input_path->total_cost,
input_path->rows);
/*
@@ -1081,9 +1082,9 @@ choose_hashed_setop(PlannerInfo *root, List *groupClauses,
sorted_p.startup_cost = input_path->startup_cost;
sorted_p.total_cost = input_path->total_cost;
/* XXX cost_sort doesn't actually look at pathkeys, so just pass NIL */
- cost_sort(&sorted_p, root, NIL, sorted_p.total_cost,
+ cost_sort(&sorted_p, root, NIL, &sorted_p.total_cost,
input_path->rows, input_path->pathtarget->width,
- 0.0, work_mem, -1.0);
+ &zerocost, work_mem, -1.0);
cost_group(&sorted_p, root, numGroupCols, dNumGroups,
NIL,
sorted_p.startup_cost, sorted_p.total_cost,
diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c
index 1890f25..099bb43 100644
--- a/src/backend/optimizer/util/appendinfo.c
+++ b/src/backend/optimizer/util/appendinfo.c
@@ -18,6 +18,7 @@
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/appendinfo.h"
+#include "optimizer/cost.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -461,7 +462,7 @@ adjust_appendrel_attrs_mutator(Node *node,
* don't reset left_ec/right_ec: each child variable is implicitly
* equivalent to its parent, so still a member of the same EC if any.
*/
- newinfo->eval_cost.startup = -1;
+ cost_zero(&newinfo->eval_cost.startup); // XXX
newinfo->norm_selec = -1;
newinfo->outer_selec = -1;
newinfo->left_em = NULL;
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index a04b622..9668762 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -370,8 +370,8 @@ get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context)
{
/* add the input expressions' cost to per-input-row costs */
cost_qual_eval_node(&argcosts, (Node *) aggref->args, context->root);
- costs->transCost.startup += argcosts.startup;
- costs->transCost.per_tuple += argcosts.per_tuple;
+ cost_add(&costs->transCost.startup, &argcosts.startup);
+ cost_add(&costs->transCost.per_tuple, &argcosts.per_tuple);
/*
* Add any filter's cost to per-input-row costs.
@@ -384,8 +384,8 @@ get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context)
{
cost_qual_eval_node(&argcosts, (Node *) aggref->aggfilter,
context->root);
- costs->transCost.startup += argcosts.startup;
- costs->transCost.per_tuple += argcosts.per_tuple;
+ cost_add(&costs->transCost.startup, &argcosts.startup);
+ cost_add(&costs->transCost.per_tuple, &argcosts.per_tuple);
}
}
@@ -397,8 +397,8 @@ get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context)
{
cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs,
context->root);
- costs->finalCost.startup += argcosts.startup;
- costs->finalCost.per_tuple += argcosts.per_tuple;
+ cost_add(&costs->finalCost.startup, &argcosts.startup);
+ cost_add(&costs->finalCost.per_tuple, &argcosts.per_tuple);
}
/*
@@ -4631,7 +4631,7 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
if (contain_subplans(param))
goto fail;
cost_qual_eval(&eval_cost, list_make1(param), NULL);
- if (eval_cost.startup + eval_cost.per_tuple >
+ if (cost_asscalar(&eval_cost.startup) + cost_asscalar(&eval_cost.per_tuple) >
10 * cpu_operator_cost)
goto fail;
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 60c93ee..6026f62 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -58,6 +58,8 @@ static List *reparameterize_pathlist_by_child(PlannerInfo *root,
RelOptInfo *child_rel);
+static Cost zerocost = {0};
+
/*****************************************************************************
* MISC. PATH UTILITIES
*****************************************************************************/
@@ -72,33 +74,33 @@ compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
{
if (criterion == STARTUP_COST)
{
- if (path1->startup_cost < path2->startup_cost)
+ if (cost_asscalar(&path1->startup_cost) < cost_asscalar(&path2->startup_cost))
return -1;
- if (path1->startup_cost > path2->startup_cost)
+ if (cost_asscalar(&path1->startup_cost) > cost_asscalar(&path2->startup_cost))
return +1;
/*
* If paths have the same startup cost (not at all unlikely), order
* them by total cost.
*/
- if (path1->total_cost < path2->total_cost)
+ if (cost_asscalar(&path1->total_cost) < cost_asscalar(&path2->total_cost))
return -1;
- if (path1->total_cost > path2->total_cost)
+ if (cost_asscalar(&path1->total_cost) > cost_asscalar(&path2->total_cost))
return +1;
}
else
{
- if (path1->total_cost < path2->total_cost)
+ if (cost_asscalar(&path1->total_cost) < cost_asscalar(&path2->total_cost))
return -1;
- if (path1->total_cost > path2->total_cost)
+ if (cost_asscalar(&path1->total_cost) > cost_asscalar(&path2->total_cost))
return +1;
/*
* If paths have the same total cost, order them by startup cost.
*/
- if (path1->startup_cost < path2->startup_cost)
+ if (cost_asscalar(&path1->startup_cost) < cost_asscalar(&path2->startup_cost))
return -1;
- if (path1->startup_cost > path2->startup_cost)
+ if (cost_asscalar(&path1->startup_cost) > cost_asscalar(&path2->startup_cost))
return +1;
}
return 0;
@@ -122,13 +124,17 @@ compare_fractional_path_costs(Path *path1, Path *path2,
if (fraction <= 0.0 || fraction >= 1.0)
return compare_path_costs(path1, path2, TOTAL_COST);
- cost1 = path1->startup_cost +
- fraction * (path1->total_cost - path1->startup_cost);
- cost2 = path2->startup_cost +
- fraction * (path2->total_cost - path2->startup_cost);
- if (cost1 < cost2)
+ cost_set_diff(&cost1, &path1->total_cost, &path1->startup_cost);
+ cost_mul_scalar(&cost1, fraction);
+ cost_add(&cost1, &path1->startup_cost);
+
+ cost_set_diff(&cost2, &path2->total_cost, &path2->startup_cost);
+ cost_mul_scalar(&cost2, fraction);
+ cost_add(&cost2, &path2->startup_cost);
+
+ if (cost_asscalar(&cost1) < cost_asscalar(&cost2))
return -1;
- if (cost1 > cost2)
+ if (cost_asscalar(&cost1) > cost_asscalar(&cost2))
return +1;
return 0;
}
@@ -172,11 +178,11 @@ compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor)
* Check total cost first since it's more likely to be different; many
* paths have zero startup cost.
*/
- if (path1->total_cost > path2->total_cost * fuzz_factor)
+ if (cost_asscalar(&path1->total_cost) > cost_asscalar(&path2->total_cost) * fuzz_factor)
{
/* path1 fuzzily worse on total cost */
if (CONSIDER_PATH_STARTUP_COST(path1) &&
- path2->startup_cost > path1->startup_cost * fuzz_factor)
+ cost_asscalar(&path2->startup_cost) > cost_asscalar(&path1->startup_cost) * fuzz_factor)
{
/* ... but path2 fuzzily worse on startup, so DIFFERENT */
return COSTS_DIFFERENT;
@@ -184,11 +190,11 @@ compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor)
/* else path2 dominates */
return COSTS_BETTER2;
}
- if (path2->total_cost > path1->total_cost * fuzz_factor)
+ if (cost_asscalar(&path2->total_cost) > cost_asscalar(&path1->total_cost) * fuzz_factor)
{
/* path2 fuzzily worse on total cost */
if (CONSIDER_PATH_STARTUP_COST(path2) &&
- path1->startup_cost > path2->startup_cost * fuzz_factor)
+ cost_asscalar(&path1->startup_cost) > cost_asscalar(&path2->startup_cost) * fuzz_factor)
{
/* ... but path1 fuzzily worse on startup, so DIFFERENT */
return COSTS_DIFFERENT;
@@ -197,12 +203,12 @@ compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor)
return COSTS_BETTER1;
}
/* fuzzily the same on total cost ... */
- if (path1->startup_cost > path2->startup_cost * fuzz_factor)
+ if (cost_asscalar(&path1->startup_cost) > cost_asscalar(&path2->startup_cost) * fuzz_factor)
{
/* ... but path1 fuzzily worse on startup, so path2 wins */
return COSTS_BETTER2;
}
- if (path2->startup_cost > path1->startup_cost * fuzz_factor)
+ if (cost_asscalar(&path2->startup_cost) > cost_asscalar(&path1->startup_cost) * fuzz_factor)
{
/* ... but path2 fuzzily worse on startup, so path1 wins */
return COSTS_BETTER1;
@@ -596,7 +602,7 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
else
{
/* new belongs after this old path if it has cost >= old's */
- if (new_path->total_cost >= old_path->total_cost)
+ if (cost_asscalar(&new_path->total_cost) >= cost_asscalar(&old_path->total_cost))
insert_at = foreach_current_index(p1) + 1;
}
@@ -668,10 +674,10 @@ add_path_precheck(RelOptInfo *parent_rel,
*
* Cost comparisons here should match compare_path_costs_fuzzily.
*/
- if (total_cost > old_path->total_cost * STD_FUZZ_FACTOR)
+ if (cost_asscalar(&total_cost) > cost_asscalar(&old_path->total_cost) * STD_FUZZ_FACTOR)
{
/* new path can win on startup cost only if consider_startup */
- if (startup_cost > old_path->startup_cost * STD_FUZZ_FACTOR ||
+ if (cost_asscalar(&startup_cost) > cost_asscalar(&old_path->startup_cost) * STD_FUZZ_FACTOR ||
!consider_startup)
{
/* new path loses on cost, so check pathkeys... */
@@ -777,13 +783,13 @@ add_partial_path(RelOptInfo *parent_rel, Path *new_path)
/* Unless pathkeys are incompatible, keep just one of the two paths. */
if (keyscmp != PATHKEYS_DIFFERENT)
{
- if (new_path->total_cost > old_path->total_cost * STD_FUZZ_FACTOR)
+ if (cost_asscalar(&new_path->total_cost) > cost_asscalar(&old_path->total_cost) * STD_FUZZ_FACTOR)
{
/* New path costs more; keep it only if pathkeys are better. */
if (keyscmp != PATHKEYS_BETTER1)
accept_new = false;
}
- else if (old_path->total_cost > new_path->total_cost
+ else if (cost_asscalar(&old_path->total_cost) > cost_asscalar(&new_path->total_cost)
* STD_FUZZ_FACTOR)
{
/* Old path costs more; keep it only if pathkeys are better. */
@@ -800,7 +806,7 @@ add_partial_path(RelOptInfo *parent_rel, Path *new_path)
/* Costs are about the same, old path has better pathkeys. */
accept_new = false;
}
- else if (old_path->total_cost > new_path->total_cost * 1.0000000001)
+ else if (cost_asscalar(&old_path->total_cost) > cost_asscalar(&new_path->total_cost) * 1.0000000001)
{
/* Pathkeys are the same, and the old path costs more. */
remove_old = true;
@@ -827,7 +833,7 @@ add_partial_path(RelOptInfo *parent_rel, Path *new_path)
else
{
/* new belongs after this old path if it has cost >= old's */
- if (new_path->total_cost >= old_path->total_cost)
+ if (cost_asscalar(&new_path->total_cost) >= cost_asscalar(&old_path->total_cost))
insert_at = foreach_current_index(p1) + 1;
}
@@ -888,10 +894,10 @@ add_partial_path_precheck(RelOptInfo *parent_rel, Cost total_cost,
keyscmp = compare_pathkeys(pathkeys, old_path->pathkeys);
if (keyscmp != PATHKEYS_DIFFERENT)
{
- if (total_cost > old_path->total_cost * STD_FUZZ_FACTOR &&
+ if (cost_asscalar(&total_cost) > cost_asscalar(&old_path->total_cost) * STD_FUZZ_FACTOR &&
keyscmp != PATHKEYS_BETTER1)
return false;
- if (old_path->total_cost > total_cost * STD_FUZZ_FACTOR &&
+ if (cost_asscalar(&old_path->total_cost) > cost_asscalar(&total_cost) * STD_FUZZ_FACTOR &&
keyscmp != PATHKEYS_BETTER2)
return true;
}
@@ -1350,8 +1356,8 @@ create_merge_append_path(PlannerInfo *root,
List *partitioned_rels)
{
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
- Cost input_startup_cost;
- Cost input_total_cost;
+ Cost input_startup_cost = {0};
+ Cost input_total_cost = {0};
ListCell *l;
pathnode->path.pathtype = T_MergeAppend;
@@ -1379,8 +1385,6 @@ create_merge_append_path(PlannerInfo *root,
* Add up the sizes and costs of the input paths.
*/
pathnode->path.rows = 0;
- input_startup_cost = 0;
- input_total_cost = 0;
foreach(l, subpaths)
{
Path *subpath = (Path *) lfirst(l);
@@ -1392,8 +1396,8 @@ create_merge_append_path(PlannerInfo *root,
if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
{
/* Subpath is adequately ordered, we won't need to sort it */
- input_startup_cost += subpath->startup_cost;
- input_total_cost += subpath->total_cost;
+ cost_add(&input_startup_cost, &subpath->startup_cost);
+ cost_add(&input_total_cost, &subpath->total_cost);
}
else
{
@@ -1403,14 +1407,14 @@ create_merge_append_path(PlannerInfo *root,
cost_sort(&sort_path,
root,
pathkeys,
- subpath->total_cost,
+ &subpath->total_cost,
subpath->parent->tuples,
subpath->pathtarget->width,
- 0.0,
+ &zerocost,
work_mem,
pathnode->limit_tuples);
- input_startup_cost += sort_path.startup_cost;
- input_total_cost += sort_path.total_cost;
+ cost_add(&input_startup_cost, &sort_path.startup_cost);
+ cost_add(&input_total_cost, &sort_path.total_cost);
}
/* All child paths must have same parameterization */
@@ -1466,8 +1470,9 @@ create_group_result_path(PlannerInfo *root, RelOptInfo *rel,
*/
pathnode->path.rows = 1;
pathnode->path.startup_cost = target->cost.startup;
- pathnode->path.total_cost = target->cost.startup +
- cpu_tuple_cost + target->cost.per_tuple;
+ cost_set_member(&pathnode->path.total_cost, cpu_tuple_cost);
+ cost_add2(&pathnode->path.total_cost, &target->cost.startup,
+ &target->cost.per_tuple);
/*
* Add cost of qual, if any --- but we ignore its selectivity, since our
@@ -1479,8 +1484,8 @@ create_group_result_path(PlannerInfo *root, RelOptInfo *rel,
cost_qual_eval(&qual_cost, havingqual, root);
/* havingqual is evaluated once at startup */
- pathnode->path.startup_cost += qual_cost.startup + qual_cost.per_tuple;
- pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
+ cost_add2(&pathnode->path.startup_cost, &qual_cost.startup, &qual_cost.per_tuple);
+ cost_add2(&pathnode->path.total_cost, &qual_cost.startup, &qual_cost.per_tuple);
}
return pathnode;
@@ -1665,10 +1670,10 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
* Estimate cost for sort+unique implementation
*/
cost_sort(&sort_path, root, NIL,
- subpath->total_cost,
+ &subpath->total_cost,
rel->rows,
subpath->pathtarget->width,
- 0.0,
+ &zerocost,
work_mem,
-1.0);
@@ -1678,7 +1683,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
* probably this is an overestimate.) This should agree with
* create_upper_unique_path.
*/
- sort_path.total_cost += cpu_operator_cost * rel->rows * numCols;
+ cost_add_member_mul(&sort_path.total_cost, cpu_operator_cost, rel->rows * numCols);
}
if (sjinfo->semi_can_hash)
@@ -1702,14 +1707,14 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
AGG_HASHED, NULL,
numCols, pathnode->path.rows,
NIL,
- subpath->startup_cost,
- subpath->total_cost,
+ &subpath->startup_cost,
+ &subpath->total_cost,
rel->rows);
}
if (sjinfo->semi_can_btree && sjinfo->semi_can_hash)
{
- if (agg_path.total_cost < sort_path.total_cost)
+ if (cost_asscalar(&agg_path.total_cost) < cost_asscalar(&sort_path.total_cost))
pathnode->umethod = UNIQUE_PATH_HASH;
else
pathnode->umethod = UNIQUE_PATH_SORT;
@@ -1755,8 +1760,8 @@ create_gather_merge_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
Relids required_outer, double *rows)
{
GatherMergePath *pathnode = makeNode(GatherMergePath);
- Cost input_startup_cost = 0;
- Cost input_total_cost = 0;
+ Cost input_startup_cost = {0};
+ Cost input_total_cost = {0};
Assert(subpath->parallel_safe);
Assert(pathkeys);
@@ -1776,8 +1781,8 @@ create_gather_merge_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
{
/* Subpath is adequately ordered, we won't need to sort it */
- input_startup_cost += subpath->startup_cost;
- input_total_cost += subpath->total_cost;
+ cost_add(&input_startup_cost, &subpath->startup_cost);
+ cost_add(&input_total_cost, &subpath->total_cost);
}
else
{
@@ -1787,14 +1792,14 @@ create_gather_merge_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
cost_sort(&sort_path,
root,
pathkeys,
- subpath->total_cost,
+ &subpath->total_cost,
subpath->rows,
subpath->pathtarget->width,
- 0.0,
+ &zerocost,
work_mem,
-1);
- input_startup_cost += sort_path.startup_cost;
- input_total_cost += sort_path.total_cost;
+ cost_add(&input_startup_cost, &sort_path.startup_cost);
+ cost_add(&input_total_cost, &sort_path.total_cost);
}
cost_gather_merge(pathnode, root, rel, pathnode->path.param_info,
@@ -2558,11 +2563,14 @@ create_projection_path(PlannerInfo *root,
* Set cost of plan as subpath's cost, adjusted for tlist replacement.
*/
pathnode->path.rows = subpath->rows;
- pathnode->path.startup_cost = subpath->startup_cost +
- (target->cost.startup - oldtarget->cost.startup);
- pathnode->path.total_cost = subpath->total_cost +
- (target->cost.startup - oldtarget->cost.startup) +
- (target->cost.per_tuple - oldtarget->cost.per_tuple) * subpath->rows;
+
+ cost_set_sum2(&pathnode->path.startup_cost, &subpath->startup_cost, &target->cost.startup);
+ cost_sub(&pathnode->path.startup_cost, &oldtarget->cost.startup);
+
+ cost_set_diff(&pathnode->path.total_cost, &target->cost.per_tuple, &oldtarget->cost.per_tuple);
+ cost_mul_scalar(&pathnode->path.total_cost, subpath->rows);
+ cost_add2(&pathnode->path.total_cost, &subpath->total_cost, &target->cost.startup);
+ cost_sub(&pathnode->path.total_cost, &oldtarget->cost.startup);
}
else
{
@@ -2574,11 +2582,12 @@ create_projection_path(PlannerInfo *root,
* evaluating the tlist. There is no qual to worry about.
*/
pathnode->path.rows = subpath->rows;
- pathnode->path.startup_cost = subpath->startup_cost +
- target->cost.startup;
- pathnode->path.total_cost = subpath->total_cost +
- target->cost.startup +
- (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows;
+
+ cost_set_sum2(&pathnode->path.startup_cost, &subpath->startup_cost, &target->cost.startup);
+
+ cost_set_member_add(&pathnode->path.total_cost, cpu_tuple_cost, &target->cost.per_tuple);
+ cost_mul_scalar(&pathnode->path.total_cost, subpath->rows);
+ cost_add2(&pathnode->path.total_cost, &subpath->total_cost, &target->cost.startup);
}
return pathnode;
@@ -2613,6 +2622,7 @@ apply_projection_to_path(PlannerInfo *root,
PathTarget *target)
{
QualCost oldcost;
+ Cost tmp;
/*
* If given path can't project, we might need a Result node, so make a
@@ -2628,9 +2638,14 @@ apply_projection_to_path(PlannerInfo *root,
oldcost = path->pathtarget->cost;
path->pathtarget = target;
- path->startup_cost += target->cost.startup - oldcost.startup;
- path->total_cost += target->cost.startup - oldcost.startup +
- (target->cost.per_tuple - oldcost.per_tuple) * path->rows;
+ cost_add(&path->startup_cost, &target->cost.startup);
+ cost_sub(&path->startup_cost, &oldcost.startup);
+
+ cost_set_diff(&tmp, &target->cost.per_tuple, &oldcost.per_tuple);
+ cost_mul_scalar(&tmp, path->rows);
+ cost_add(&path->total_cost, &target->cost.startup);
+ cost_sub(&path->total_cost, &oldcost.startup);
+ cost_add(&path->total_cost, &tmp);
/*
* If the path happens to be a Gather or GatherMerge path, we'd like to
@@ -2704,6 +2719,7 @@ create_set_projection_path(PlannerInfo *root,
ProjectSetPath *pathnode = makeNode(ProjectSetPath);
double tlist_rows;
ListCell *lc;
+ Cost tmp;
pathnode->path.pathtype = T_ProjectSet;
pathnode->path.parent = rel;
@@ -2742,12 +2758,15 @@ create_set_projection_path(PlannerInfo *root,
* this estimate later.
*/
pathnode->path.rows = subpath->rows * tlist_rows;
- pathnode->path.startup_cost = subpath->startup_cost +
- target->cost.startup;
- pathnode->path.total_cost = subpath->total_cost +
- target->cost.startup +
- (cpu_tuple_cost + target->cost.per_tuple) * subpath->rows +
- (pathnode->path.rows - subpath->rows) * cpu_tuple_cost / 2;
+
+ cost_set_sum2(&pathnode->path.startup_cost, &subpath->startup_cost,
+ &target->cost.startup);
+ cost_set_sum2(&pathnode->path.total_cost, &subpath->total_cost, &target->cost.startup);
+
+ cost_set_member_add(&tmp, cpu_tuple_cost, &target->cost.per_tuple);
+ cost_add_mul(&pathnode->path.total_cost, &tmp, subpath->rows);
+
+ cost_add_member_mul(&pathnode->path.total_cost, cpu_tuple_cost, 0.5 * (pathnode->path.rows - subpath->rows) );
return pathnode;
}
@@ -2786,10 +2805,10 @@ create_sort_path(PlannerInfo *root,
pathnode->subpath = subpath;
cost_sort(&pathnode->path, root, pathkeys,
- subpath->total_cost,
+ &subpath->total_cost,
subpath->rows,
subpath->pathtarget->width,
- 0.0, /* XXX comparison_cost shouldn't be 0? */
+ &zerocost, /* XXX comparison_cost shouldn't be 0? */
work_mem, limit_tuples);
return pathnode;
@@ -2842,9 +2861,9 @@ create_group_path(PlannerInfo *root,
subpath->rows);
/* add tlist eval cost for each output row */
- pathnode->path.startup_cost += target->cost.startup;
- pathnode->path.total_cost += target->cost.startup +
- target->cost.per_tuple * pathnode->path.rows;
+ cost_add(&pathnode->path.startup_cost, &target->cost.startup);
+ cost_add(&pathnode->path.total_cost, &target->cost.startup);
+ cost_add_mul(&pathnode->path.total_cost, &target->cost.per_tuple, pathnode->path.rows);
return pathnode;
}
@@ -2896,8 +2915,8 @@ create_upper_unique_path(PlannerInfo *root,
* an overestimate.)
*/
pathnode->path.startup_cost = subpath->startup_cost;
- pathnode->path.total_cost = subpath->total_cost +
- cpu_operator_cost * subpath->rows * numCols;
+ pathnode->path.total_cost = subpath->total_cost;
+ cost_add_member_mul(&pathnode->path.total_cost, cpu_operator_cost, subpath->rows * numCols);
pathnode->path.rows = numGroups;
return pathnode;
@@ -2956,13 +2975,13 @@ create_agg_path(PlannerInfo *root,
aggstrategy, aggcosts,
list_length(groupClause), numGroups,
qual,
- subpath->startup_cost, subpath->total_cost,
+ &subpath->startup_cost, &subpath->total_cost,
subpath->rows);
/* add tlist eval cost for each output row */
- pathnode->path.startup_cost += target->cost.startup;
- pathnode->path.total_cost += target->cost.startup +
- target->cost.per_tuple * pathnode->path.rows;
+ cost_add(&pathnode->path.startup_cost, &target->cost.startup);
+ cost_add(&pathnode->path.total_cost, &target->cost.startup);
+ cost_add_mul(&pathnode->path.total_cost, &target->cost.per_tuple, pathnode->path.rows);
return pathnode;
}
@@ -3065,8 +3084,8 @@ create_groupingsets_path(PlannerInfo *root,
numGroupCols,
rollup->numGroups,
having_qual,
- subpath->startup_cost,
- subpath->total_cost,
+ &subpath->startup_cost,
+ &subpath->total_cost,
subpath->rows);
is_first = false;
if (!rollup->is_hashed)
@@ -3089,7 +3108,7 @@ create_groupingsets_path(PlannerInfo *root,
numGroupCols,
rollup->numGroups,
having_qual,
- 0.0, 0.0,
+ &zerocost, &zerocost,
subpath->rows);
if (!rollup->is_hashed)
is_first_sort = false;
@@ -3098,10 +3117,10 @@ create_groupingsets_path(PlannerInfo *root,
{
/* Account for cost of sort, but don't charge input cost again */
cost_sort(&sort_path, root, NIL,
- 0.0,
+ &zerocost,
subpath->rows,
subpath->pathtarget->width,
- 0.0,
+ &zerocost,
work_mem,
-1.0);
@@ -3113,20 +3132,20 @@ create_groupingsets_path(PlannerInfo *root,
numGroupCols,
rollup->numGroups,
having_qual,
- sort_path.startup_cost,
- sort_path.total_cost,
+ &sort_path.startup_cost,
+ &sort_path.total_cost,
sort_path.rows);
}
- pathnode->path.total_cost += agg_path.total_cost;
+ cost_add(&pathnode->path.total_cost, &agg_path.total_cost);
pathnode->path.rows += agg_path.rows;
}
}
/* add tlist eval cost for each output row */
- pathnode->path.startup_cost += target->cost.startup;
- pathnode->path.total_cost += target->cost.startup +
- target->cost.per_tuple * pathnode->path.rows;
+ cost_add(&pathnode->path.startup_cost, &target->cost.startup);
+ cost_add(&pathnode->path.total_cost, &target->cost.startup);
+ cost_add_mul(&pathnode->path.total_cost, &target->cost.per_tuple, pathnode->path.rows);
return pathnode;
}
@@ -3169,18 +3188,18 @@ create_minmaxagg_path(PlannerInfo *root,
pathnode->quals = quals;
/* Calculate cost of all the initplans ... */
- initplan_cost = 0;
+ cost_zero(&initplan_cost); // = zerocost?
foreach(lc, mmaggregates)
{
MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
- initplan_cost += mminfo->pathcost;
+ cost_add(&initplan_cost, &mminfo->pathcost);
}
/* add tlist eval cost for each output row, plus cpu_tuple_cost */
- pathnode->path.startup_cost = initplan_cost + target->cost.startup;
- pathnode->path.total_cost = initplan_cost + target->cost.startup +
- target->cost.per_tuple + cpu_tuple_cost;
+ cost_set_sum2(&pathnode->path.startup_cost, &initplan_cost, &target->cost.startup);
+ cost_set_sum3(&pathnode->path.total_cost, &initplan_cost, &target->cost.startup, &target->cost.per_tuple);
+ cost_add_member(&pathnode->path.total_cost, cpu_tuple_cost);
/*
* Add cost of qual, if any --- but we ignore its selectivity, since our
@@ -3191,8 +3210,8 @@ create_minmaxagg_path(PlannerInfo *root,
QualCost qual_cost;
cost_qual_eval(&qual_cost, quals, root);
- pathnode->path.startup_cost += qual_cost.startup;
- pathnode->path.total_cost += qual_cost.startup + qual_cost.per_tuple;
+ cost_add(&pathnode->path.startup_cost, &qual_cost.startup);
+ cost_add2(&pathnode->path.total_cost, &qual_cost.startup, &qual_cost.per_tuple);
}
return pathnode;
@@ -3251,9 +3270,9 @@ create_windowagg_path(PlannerInfo *root,
subpath->rows);
/* add tlist eval cost for each output row */
- pathnode->path.startup_cost += target->cost.startup;
- pathnode->path.total_cost += target->cost.startup +
- target->cost.per_tuple * pathnode->path.rows;
+ cost_add(&pathnode->path.startup_cost, &target->cost.startup);
+ cost_add(&pathnode->path.total_cost, &target->cost.startup);
+ cost_add_mul(&pathnode->path.total_cost, &target->cost.per_tuple, pathnode->path.rows);
return pathnode;
}
@@ -3314,8 +3333,8 @@ create_setop_path(PlannerInfo *root,
* all columns get compared at most of the tuples.
*/
pathnode->path.startup_cost = subpath->startup_cost;
- pathnode->path.total_cost = subpath->total_cost +
- cpu_operator_cost * subpath->rows * list_length(distinctList);
+ pathnode->path.total_cost = subpath->total_cost;
+ cost_add_member_mul(&pathnode->path.total_cost, cpu_operator_cost, subpath->rows * list_length(distinctList));
pathnode->path.rows = outputRows;
return pathnode;
@@ -3413,8 +3432,8 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
* cpu_tuple_cost per row.
*/
pathnode->path.startup_cost = subpath->startup_cost;
- pathnode->path.total_cost = subpath->total_cost +
- cpu_tuple_cost * subpath->rows;
+ pathnode->path.total_cost = subpath->total_cost;
+ cost_add_member_mul(&pathnode->path.total_cost, cpu_tuple_cost, subpath->rows);
return pathnode;
}
@@ -3482,8 +3501,8 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
* costs to change any higher-level planning choices. But we might want
* to make it look better sometime.
*/
- pathnode->path.startup_cost = 0;
- pathnode->path.total_cost = 0;
+ cost_zero(&pathnode->path.startup_cost); // = zerocost?
+ cost_zero(&pathnode->path.total_cost); // = zerocost?
pathnode->path.rows = 0;
total_size = 0;
foreach(lc, subpaths)
@@ -3492,7 +3511,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
if (lc == list_head(subpaths)) /* first node? */
pathnode->path.startup_cost = subpath->startup_cost;
- pathnode->path.total_cost += subpath->total_cost;
+ cost_add(&pathnode->path.total_cost, &subpath->total_cost);
pathnode->path.rows += subpath->rows;
total_size += subpath->pathtarget->width * subpath->rows;
}
@@ -3615,10 +3634,11 @@ adjust_limit_rows_costs(double *rows, /* in/out parameter */
offset_rows = clamp_row_est(input_rows * 0.10);
if (offset_rows > *rows)
offset_rows = *rows;
- if (input_rows > 0)
- *startup_cost +=
- (input_total_cost - input_startup_cost)
- * offset_rows / input_rows;
+ if (input_rows > 0) {
+ Cost tmp;
+ cost_set_diff(&tmp, &input_total_cost, &input_startup_cost);
+ cost_add_mul(startup_cost, &tmp, offset_rows / input_rows);
+ }
*rows -= offset_rows;
if (*rows < 1)
*rows = 1;
@@ -3634,10 +3654,12 @@ adjust_limit_rows_costs(double *rows, /* in/out parameter */
count_rows = clamp_row_est(input_rows * 0.10);
if (count_rows > *rows)
count_rows = *rows;
- if (input_rows > 0)
- *total_cost = *startup_cost +
- (input_total_cost - input_startup_cost)
- * count_rows / input_rows;
+
+ if (input_rows > 0) {
+ cost_set_diff(total_cost, &input_total_cost, &input_startup_cost);
+ cost_mul_scalar(total_cost, count_rows / input_rows);
+ cost_add(total_cost, startup_cost);
+ }
*rows = count_rows;
if (*rows < 1)
*rows = 1;
diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c
index 798aa8c..bd3e712 100644
--- a/src/backend/optimizer/util/placeholder.c
+++ b/src/backend/optimizer/util/placeholder.c
@@ -447,8 +447,8 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
cost_qual_eval_node(&cost, (Node *) phinfo->ph_var->phexpr,
root);
- joinrel->reltarget->cost.startup += cost.startup;
- joinrel->reltarget->cost.per_tuple += cost.per_tuple;
+ cost_add(&joinrel->reltarget->cost.startup, &cost.startup);
+ cost_add(&joinrel->reltarget->cost.per_tuple, &cost.per_tuple);
}
/* Adjust joinrel's direct_lateral_relids as needed */
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 5e889d1..5c7c000 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1924,8 +1924,8 @@ add_function_cost(PlannerInfo *root, Oid funcid, Node *node,
req.node = node;
/* Initialize cost fields so that support function doesn't have to */
- req.startup = 0;
- req.per_tuple = 0;
+ cost_zero(&req.startup);
+ cost_zero(&req.per_tuple);
sresult = (SupportRequestCost *)
DatumGetPointer(OidFunctionCall1(procform->prosupport,
@@ -1934,15 +1934,15 @@ add_function_cost(PlannerInfo *root, Oid funcid, Node *node,
if (sresult == &req)
{
/* Success, so accumulate support function's estimate into *cost */
- cost->startup += req.startup;
- cost->per_tuple += req.per_tuple;
+ cost_add(&cost->startup, &req.startup);
+ cost_add(&cost->per_tuple, &req.per_tuple);
ReleaseSysCache(proctup);
return;
}
}
/* No support function, or it failed, so rely on procost */
- cost->per_tuple += procform->procost * cpu_operator_cost;
+ cost_add_member_mul(&cost->per_tuple, cpu_operator_cost, procform->procost);
ReleaseSysCache(proctup);
}
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index c9eb447..c5bf171 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -233,8 +233,8 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
rel->unique_for_rels = NIL;
rel->non_unique_for_rels = NIL;
rel->baserestrictinfo = NIL;
- rel->baserestrictcost.startup = 0;
- rel->baserestrictcost.per_tuple = 0;
+ cost_zero(&rel->baserestrictcost.startup);
+ cost_zero(&rel->baserestrictcost.per_tuple);
rel->baserestrict_min_security = UINT_MAX;
rel->joininfo = NIL;
rel->has_eclass_joins = false;
@@ -645,8 +645,8 @@ build_join_rel(PlannerInfo *root,
joinrel->unique_for_rels = NIL;
joinrel->non_unique_for_rels = NIL;
joinrel->baserestrictinfo = NIL;
- joinrel->baserestrictcost.startup = 0;
- joinrel->baserestrictcost.per_tuple = 0;
+ cost_zero(&joinrel->baserestrictcost.startup);
+ cost_zero(&joinrel->baserestrictcost.per_tuple);
joinrel->baserestrict_min_security = UINT_MAX;
joinrel->joininfo = NIL;
joinrel->has_eclass_joins = false;
@@ -822,8 +822,8 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
joinrel->fdwroutine = NULL;
joinrel->fdw_private = NULL;
joinrel->baserestrictinfo = NIL;
- joinrel->baserestrictcost.startup = 0;
- joinrel->baserestrictcost.per_tuple = 0;
+ cost_zero(&joinrel->baserestrictcost.startup);
+ cost_zero(&joinrel->baserestrictcost.per_tuple);
joinrel->joininfo = NIL;
joinrel->has_eclass_joins = false;
joinrel->consider_partitionwise_join = false; /* might get changed later */
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index 3b50fd2..01a1a76 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -17,6 +17,7 @@
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
+#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/restrictinfo.h"
@@ -183,7 +184,7 @@ make_restrictinfo_internal(Expr *clause,
*/
restrictinfo->parent_ec = NULL;
- restrictinfo->eval_cost.startup = -1;
+ cost_zero(&restrictinfo->eval_cost.startup); // XXX
restrictinfo->norm_selec = -1;
restrictinfo->outer_selec = -1;
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index ff02b5a..2df6f0e 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -5592,12 +5592,12 @@ get_quals_from_indexclauses(List *indexclauses)
* or directly on an indexorderbys list. In both cases, we expect that the
* index key expression is on the left side of binary clauses.
*/
-Cost
-index_other_operands_eval_cost(PlannerInfo *root, List *indexquals)
+void
+index_other_operands_eval_cost(PlannerInfo *root, List *indexquals, Cost *qual_arg_cost)
{
- Cost qual_arg_cost = 0;
ListCell *lc;
+ cost_zero(qual_arg_cost);
foreach(lc, indexquals)
{
Expr *clause = (Expr *) lfirst(lc);
@@ -5641,9 +5641,8 @@ index_other_operands_eval_cost(PlannerInfo *root, List *indexquals)
}
cost_qual_eval_node(&index_qual_cost, other_operand, root);
- qual_arg_cost += index_qual_cost.startup + index_qual_cost.per_tuple;
+ cost_add2(qual_arg_cost, &index_qual_cost.startup, &index_qual_cost.per_tuple);
}
- return qual_arg_cost;
}
void
@@ -5665,8 +5664,9 @@ genericcostestimate(PlannerInfo *root,
double num_sa_scans;
double num_outer_scans;
double num_scans;
- double qual_op_cost;
- double qual_arg_cost;
+ Cost qual_op_cost;
+ Cost qual_arg_cost;
+ Cost tmp;
List *selectivityQuals;
ListCell *l;
@@ -5792,8 +5792,7 @@ genericcostestimate(PlannerInfo *root,
* share for each outer scan. (Don't pro-rate for ScalarArrayOpExpr,
* since that's internal to the indexscan.)
*/
- indexTotalCost = (pages_fetched * spc_random_page_cost)
- / num_outer_scans;
+ cost_add_member_mul_spc(&indexTotalCost, spc_, random_page_cost, pages_fetched/num_outer_scans);
}
else
{
@@ -5801,7 +5800,7 @@ genericcostestimate(PlannerInfo *root,
* For a single index scan, we just charge spc_random_page_cost per
* page touched.
*/
- indexTotalCost = numIndexPages * spc_random_page_cost;
+ cost_add_member_mul_spc(&indexTotalCost, spc_, random_page_cost, numIndexPages);
}
/*
@@ -5818,14 +5817,16 @@ genericcostestimate(PlannerInfo *root,
* Detecting that that might be needed seems more expensive than it's
* worth, though, considering all the other inaccuracies here ...
*/
- qual_arg_cost = index_other_operands_eval_cost(root, indexQuals) +
- index_other_operands_eval_cost(root, indexOrderBys);
- qual_op_cost = cpu_operator_cost *
- (list_length(indexQuals) + list_length(indexOrderBys));
+ index_other_operands_eval_cost(root, indexQuals, &qual_arg_cost);
+ index_other_operands_eval_cost(root, indexOrderBys, &tmp);
+ cost_add(&qual_arg_cost, &tmp);
+
+ cost_set_member_mul(&qual_op_cost, cpu_operator_cost, list_length(indexQuals) + list_length(indexOrderBys));
indexStartupCost = qual_arg_cost;
- indexTotalCost += qual_arg_cost;
- indexTotalCost += numIndexTuples * num_sa_scans * (cpu_index_tuple_cost + qual_op_cost);
+ cost_add(&indexTotalCost, &qual_arg_cost);
+ cost_add_mul(&indexTotalCost, &qual_op_cost, numIndexTuples * num_sa_scans);
+ cost_add_member_mul(&indexTotalCost, cpu_index_tuple_cost, numIndexTuples * num_sa_scans);
/*
* Generic assumption about index correlation: there isn't any.
@@ -6065,9 +6066,9 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
*/
if (index->tuples > 1) /* avoid computing log(0) */
{
- descentCost = ceil(log(index->tuples) / log(2.0)) * cpu_operator_cost;
- costs.indexStartupCost += descentCost;
- costs.indexTotalCost += costs.num_sa_scans * descentCost;
+ cost_set_member_mul(&descentCost, cpu_operator_cost, ceil(log(index->tuples) / log(2.0)));
+ cost_add(&costs.indexStartupCost, &descentCost);
+ cost_add_mul(&costs.indexTotalCost, &descentCost, costs.num_sa_scans);
}
/*
@@ -6080,9 +6081,9 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
* touched. The number of such pages is btree tree height plus one (ie,
* we charge for the leaf page too). As above, charge once per SA scan.
*/
- descentCost = (index->tree_height + 1) * 50.0 * cpu_operator_cost;
- costs.indexStartupCost += descentCost;
- costs.indexTotalCost += costs.num_sa_scans * descentCost;
+ cost_set_member_mul(&descentCost, cpu_operator_cost, (index->tree_height + 1) * 50.0);
+ cost_add(&costs.indexStartupCost, &descentCost);
+ cost_add_mul(&costs.indexTotalCost, &descentCost, costs.num_sa_scans);
/*
* If we can get an estimate of the first column's ordering correlation C
@@ -6273,17 +6274,17 @@ gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
*/
if (index->tuples > 1) /* avoid computing log(0) */
{
- descentCost = ceil(log(index->tuples)) * cpu_operator_cost;
- costs.indexStartupCost += descentCost;
- costs.indexTotalCost += costs.num_sa_scans * descentCost;
+ cost_set_member_mul(&descentCost, cpu_operator_cost, ceil(log(index->tuples)));
+ cost_add(&costs.indexStartupCost, &descentCost);
+ cost_add_mul(&costs.indexTotalCost, &descentCost, costs.num_sa_scans);
}
/*
* Likewise add a per-page charge, calculated the same as for btrees.
*/
- descentCost = (index->tree_height + 1) * 50.0 * cpu_operator_cost;
- costs.indexStartupCost += descentCost;
- costs.indexTotalCost += costs.num_sa_scans * descentCost;
+ cost_set_member_mul(&descentCost, cpu_operator_cost, (index->tree_height + 1) * 50.0);
+ cost_add(&costs.indexStartupCost, &descentCost);
+ cost_add_mul(&costs.indexTotalCost, &descentCost, costs.num_sa_scans);
*indexStartupCost = costs.indexStartupCost;
*indexTotalCost = costs.indexTotalCost;
@@ -6330,17 +6331,17 @@ spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
*/
if (index->tuples > 1) /* avoid computing log(0) */
{
- descentCost = ceil(log(index->tuples)) * cpu_operator_cost;
- costs.indexStartupCost += descentCost;
- costs.indexTotalCost += costs.num_sa_scans * descentCost;
+ cost_set_member_mul(&descentCost, cpu_operator_cost, ceil(log(index->tuples)));
+ cost_add(&costs.indexStartupCost, &descentCost);
+ cost_add_mul(&costs.indexTotalCost, &descentCost, costs.num_sa_scans);
}
/*
* Likewise add a per-page charge, calculated the same as for btrees.
*/
- descentCost = (index->tree_height + 1) * 50.0 * cpu_operator_cost;
- costs.indexStartupCost += descentCost;
- costs.indexTotalCost += costs.num_sa_scans * descentCost;
+ cost_set_member_mul(&descentCost, cpu_operator_cost, (index->tree_height + 1) * 50.0);
+ cost_add(&costs.indexStartupCost, &descentCost);
+ cost_add_mul(&costs.indexTotalCost, &descentCost, costs.num_sa_scans);
*indexStartupCost = costs.indexStartupCost;
*indexTotalCost = costs.indexTotalCost;
@@ -6658,9 +6659,9 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
double entryPagesFetched,
dataPagesFetched,
dataPagesFetchedBySel;
- double qual_op_cost,
- qual_arg_cost,
- spc_random_page_cost,
+ Cost qual_op_cost,
+ qual_arg_cost;
+ double spc_random_page_cost,
outer_scans;
Relation indexRel;
GinStatsData ginStats;
@@ -6815,9 +6816,9 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
/* Fall out if there were any provably-unsatisfiable quals */
if (!matchPossible)
{
- *indexStartupCost = 0;
- *indexTotalCost = 0;
- *indexSelectivity = 0;
+ cost_zero(indexStartupCost);
+ cost_zero(indexTotalCost);
+ indexSelectivity = 0;
return;
}
@@ -6892,7 +6893,7 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
* Here we use random page cost because logically-close pages could be far
* apart on disk.
*/
- *indexStartupCost = (entryPagesFetched + dataPagesFetched) * spc_random_page_cost;
+ cost_set_member_mul_spc(indexStartupCost, spc_, random_page_cost, entryPagesFetched + dataPagesFetched);
/*
* Now compute the number of data pages fetched during the scan.
@@ -6931,19 +6932,20 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
}
/* And apply random_page_cost as the cost per page */
- *indexTotalCost = *indexStartupCost +
- dataPagesFetched * spc_random_page_cost;
+ *indexTotalCost = *indexStartupCost;
+ cost_add_member_mul_spc(indexTotalCost, spc_, random_page_cost, dataPagesFetched);
/*
* Add on index qual eval costs, much as in genericcostestimate. But we
* can disregard indexorderbys, since GIN doesn't support those.
*/
- qual_arg_cost = index_other_operands_eval_cost(root, indexQuals);
- qual_op_cost = cpu_operator_cost * list_length(indexQuals);
+ index_other_operands_eval_cost(root, indexQuals, &qual_arg_cost);
+ cost_set_member_mul(&qual_op_cost, cpu_operator_cost, list_length(indexQuals));
- *indexStartupCost += qual_arg_cost;
- *indexTotalCost += qual_arg_cost;
- *indexTotalCost += (numTuples * *indexSelectivity) * (cpu_index_tuple_cost + qual_op_cost);
+ cost_add(indexStartupCost, &qual_arg_cost);
+ cost_add(indexTotalCost, &qual_arg_cost);
+ cost_add_mul(indexTotalCost, &qual_op_cost, *indexSelectivity * numTuples);
+ cost_add_member_mul(indexTotalCost, cpu_index_tuple_cost, *indexSelectivity * numTuples);
*indexPages = dataPagesFetched;
}
@@ -6961,9 +6963,9 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
double numPages = index->pages;
RelOptInfo *baserel = index->rel;
RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root);
- Cost spc_seq_page_cost;
- Cost spc_random_page_cost;
- double qual_arg_cost;
+ double spc_seq_page_cost;
+ double spc_random_page_cost;
+ Cost qual_arg_cost;
double qualSelectivity;
BrinStatsData statsData;
double indexRanges;
@@ -7137,23 +7139,23 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
* the index costs. We can disregard indexorderbys, since BRIN doesn't
* support those.
*/
- qual_arg_cost = index_other_operands_eval_cost(root, indexQuals);
+ index_other_operands_eval_cost(root, indexQuals, &qual_arg_cost);
/*
* Compute the startup cost as the cost to read the whole revmap
* sequentially, including the cost to execute the index quals.
*/
- *indexStartupCost =
- spc_seq_page_cost * statsData.revmapNumPages * loop_count;
- *indexStartupCost += qual_arg_cost;
+ cost_set_member_mul_spc(indexStartupCost,
+ spc_, seq_page_cost, statsData.revmapNumPages * loop_count);
+ cost_add(indexStartupCost, &qual_arg_cost);
/*
* To read a BRIN index there might be a bit of back and forth over
* regular pages, as revmap might point to them out of sequential order;
* calculate the total cost as reading the whole index in random order.
*/
- *indexTotalCost = *indexStartupCost +
- spc_random_page_cost * (numPages - statsData.revmapNumPages) * loop_count;
+ *indexTotalCost = *indexStartupCost;
+ cost_add_member_mul_spc(indexTotalCost, spc_, random_page_cost, (numPages - statsData.revmapNumPages) * loop_count);
/*
* Charge a small amount per range tuple which we expect to match to. This
@@ -7162,8 +7164,8 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
* range, so we must multiply the charge by the number of pages in the
* range.
*/
- *indexTotalCost += 0.1 * cpu_operator_cost * estimatedRanges *
- statsData.pagesPerRange;
+ cost_add_member_mul(indexTotalCost, cpu_operator_cost, 0.1 * estimatedRanges *
+ statsData.pagesPerRange);
*indexPages = index->pages;
}
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index abc3062..c9b24dd 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -62,6 +62,7 @@
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
+#include "optimizer/cost.h"
#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "storage/lmgr.h"
@@ -1082,7 +1083,7 @@ cached_plan_cost(CachedPlan *plan, bool include_planner)
if (plannedstmt->commandType == CMD_UTILITY)
continue; /* Ignore utility statements */
- result += plannedstmt->planTree->total_cost;
+ result += cost_asscalar(&plannedstmt->planTree->total_cost);
if (include_planner)
{
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index bce2d59..f895951 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -656,7 +656,21 @@ extern bool equal(const void *a, const void *b);
* depend on them...
*/
typedef double Selectivity; /* fraction of tuples a qualifier will pass */
-typedef double Cost; /* execution cost (in page-access units) */
+
+/* execution cost (in page-access units) */
+/* these could be ints to be multipled by associated cost parameter */
+typedef struct {
+ double cpu_index_tuple_cost;
+ double cpu_operator_cost;
+ double cpu_tuple_cost;
+ double parallel_setup_cost;
+ // bool parallel_setup_cost;
+ double parallel_tuple_cost;
+ double random_page_cost;
+ double seq_page_cost;
+ double disable_cost;
+ // bool disable_cost;
+} Cost;
/*
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index b3d0b4f..4a4be15 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -45,7 +45,7 @@ typedef enum
*/
/* parameter variables and flags (see also optimizer.h) */
-extern PGDLLIMPORT Cost disable_cost;
+extern PGDLLIMPORT double disable_cost;
extern PGDLLIMPORT int max_parallel_workers_per_gather;
extern PGDLLIMPORT bool enable_seqscan;
extern PGDLLIMPORT bool enable_indexscan;
@@ -98,8 +98,8 @@ extern void cost_resultscan(Path *path, PlannerInfo *root,
RelOptInfo *baserel, ParamPathInfo *param_info);
extern void cost_recursive_union(Path *runion, Path *nrterm, Path *rterm);
extern void cost_sort(Path *path, PlannerInfo *root,
- List *pathkeys, Cost input_cost, double tuples, int width,
- Cost comparison_cost, int sort_mem,
+ List *pathkeys, Cost *input_cost, double tuples, int width,
+ Cost *comparison_cost, int sort_mem,
double limit_tuples);
extern void cost_append(AppendPath *path);
extern void cost_merge_append(Path *path, PlannerInfo *root,
@@ -113,7 +113,7 @@ extern void cost_agg(Path *path, PlannerInfo *root,
AggStrategy aggstrategy, const AggClauseCosts *aggcosts,
int numGroupCols, double numGroups,
List *quals,
- Cost input_startup_cost, Cost input_total_cost,
+ Cost *input_startup_cost, Cost *input_total_cost,
double input_tuples);
extern void cost_windowagg(Path *path, PlannerInfo *root,
List *windowFuncs, int numPartCols, int numOrderCols,
@@ -196,5 +196,28 @@ extern void set_foreign_size_estimates(PlannerInfo *root, RelOptInfo *rel);
extern PathTarget *set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target);
extern double compute_bitmap_pages(PlannerInfo *root, RelOptInfo *baserel,
Path *bitmapqual, int loop_count, Cost *cost, double *tuple);
+#define cost_add_member(cost,member) (cost)->member += member
+#define cost_add_member_mul(cost,member,mul) (cost)->member += member*mul
+#define cost_add_member_mul_spc(cost,spc,member,mul) (cost)->member += spc##member*mul
+
+#define cost_set_member(cost,member) do{ cost_zero(cost); (cost)->member = member; } while(0);
+#define cost_set_member_mul(cost,member,mul) do{ cost_zero(cost); (cost)->member = member*mul; } while(0);
+#define cost_set_member_mul_spc(cost,spc,member,mul) do{ cost_zero(cost); (cost)->member = spc##member*mul; } while(0);
+#define cost_set_member_add(cost,member,from1) do{ *cost = *from1; (cost)->member += member; } while(0);
+
+extern void cost_zero(Cost *to);
+extern void cost_set_sum2(Cost *to, const Cost *from1, const Cost *from2);
+extern void cost_set_sum3(Cost *to, const Cost *from1, const Cost *from2, const Cost *from3);
+extern void cost_set_diff(Cost *to, const Cost *from1, const Cost *from2);
+extern void cost_add(Cost *to, const Cost *from);
+extern void cost_add2(Cost *to, const Cost *from1, const Cost *from2);
+extern void cost_add_mul(Cost *to, const Cost *from, double multiplier);
+extern void cost_sub(Cost *to, const Cost *from);
+extern void cost_mul_scalar(Cost *to, double by);
+
+/* Comparison */
+extern bool cost_isgt(const Cost *to, const Cost *than);
+extern bool cost_islt(const Cost *to, const Cost *than);
+extern double cost_asscalar(const Cost *to);
#endif /* COST_H */
diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h
index 353d38a..e08077c 100644
--- a/src/include/utils/selfuncs.h
+++ b/src/include/utils/selfuncs.h
@@ -192,8 +192,9 @@ extern double estimate_hashagg_tablesize(Path *path,
double dNumGroups);
extern List *get_quals_from_indexclauses(List *indexclauses);
-extern Cost index_other_operands_eval_cost(PlannerInfo *root,
- List *indexquals);
+extern void index_other_operands_eval_cost(PlannerInfo *root,
+ List *indexquals,
+ Cost *qual_arg_cost);
extern List *add_predicate_to_index_quals(IndexOptInfo *index,
List *indexQuals);
extern void genericcostestimate(PlannerInfo *root, IndexPath *path,
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 2f66d76..59f9140 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -31,6 +31,7 @@
#include "executor/spi.h"
#include "miscadmin.h"
#include "nodes/supportnodes.h"
+#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/plancat.h"
#include "port/atomics.h"
@@ -853,8 +854,8 @@ test_support_func(PG_FUNCTION_ARGS)
/* Provide some generic estimate */
SupportRequestCost *req = (SupportRequestCost *) rawreq;
- req->startup = 0;
- req->per_tuple = 2 * cpu_operator_cost;
+ cost_zero(&req->startup);
+ cost_add_member_mul(&req->per_tuple, cpu_operator_cost, 2);
ret = (Node *) req;
}
--
2.7.4