Обсуждение: verbose cost estimate

Поиск
Список
Период
Сортировка

verbose cost estimate

От
Justin Pryzby
Дата:
Jeff said:
https://www.postgresql.org/message-id/CAMkU%3D1zBJNVo2DGYBgLJqpu8fyjCE_ys%2Bmsr6pOEoiwA7y5jrA%40mail.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



Re: verbose cost estimate

От
Tom Lane
Дата:
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



Re: verbose cost estimate

От
Jim Finnerty
Дата:
+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



Re: verbose cost estimate

От
Tom Lane
Дата:
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



Re: verbose cost estimate

От
Robert Haas
Дата:
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



Re: verbose cost estimate

От
Tomas Vondra
Дата:
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 



Re: verbose cost estimate

От
Greg Stark
Дата:
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



Re: verbose cost estimate

От
Tom Lane
Дата:
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



Re: verbose cost estimate

От
Tomas Vondra
Дата:
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 



Re: verbose cost estimate

От
Tomas Vondra
Дата:
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 



Re: verbose cost estimate

От
Justin Pryzby
Дата:
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

Вложения