Re: Parallel Aggregates for string_agg and array_agg

Tomer Praizler <[email protected]> Thu, 14 Mar 2019 01:43:12 +0200
Newsgroups gmane.comp.db.postgresql.novice
Message-ID <CAD=kdR8qQehNXLCXj5tM92ZWh8cB4OFVNNQjC-T6ZRgZiOghtg@mail.gmail.com>
Thank you, David!
I guess I wasn't 100% clear, an example will do the trick.

So let's take for example the following records:

timestamp                      port     super_name   name      ids    count
2019-03-06 10:00:00      22             ssh            abc        1,2     10
2019-03-06 10:00:00      22             ssh            xyz         3,4
 20
2019-03-06 10:00:00      22             ssh            abc        5,6     30
2019-03-06 10:00:00      22             ssh            abc        7,8     40
2019-03-06 10:00:00      22             ssh            foo        9,10    50


The primary key is combined of 6 columns in this example: (timestamp, port,
super_name), I have around 8 values for every key.
My table is partitioned by day, and I have around 2-3M rows in each
partition. I am trying to aggregate on the last 7 days, which is around 23M
rows.

my query looks something like this:

SELECT x.timestamp, x.port, x.super_name, max(x.timestamp) AS last_seen,
coalesce(array_length(array_merge_agg(x.ids), 1), 0) AS my_count,
coalesce(array_length(array_agg(DISTINCT x.name), 1), 0) AS names,
sum(x.count) AS final_count
FROM x
GROUP BY x.timestamp, x.port, x.super_name
ORDER BY sum(x.count)

This result in a plan without parallel execution because of the array_agg
on a string field. when I remove it the query planner spawns a
parallel execution plan.
It reduces the time from 5 minutes to around 1 minute which is also a lot.
(if there is any idea on how to optimize farther please help:) btw,
hardware resources is not a problem)

Thanks!


On Thu, 14 Mar 2019 at 01:02 David Rowley <[email protected]>
wrote:

> On Thu, 14 Mar 2019 at 09:53, Tomer Praizler <[email protected]>
> wrote:
> > Just wanted to check if there is any magic that can be done to make this
> happen.
> > The closest thing I ran into was this guy patch -
> https://www.postgresql.org/message-id/CAKJS1f8LV7AT%3DAAhdYGKtGrGkSkEgO6C_SW2Ztz1sR3encisqw%40mail.gmail.com
>
> If you're able to change the SQLs and point them at some other
> aggregate function, then you could create an extension with the code
> from that patch and CREATE AGGREGATE your own version of those
> functions using the combine and [de]serial functions.  I know that
> creating your own extension is pretty out there for the novice mailing
> list, but if I thought of another easier way if have told you that
> instead.
>
> > I didn't try it, but wanted to check if there is any way to deal with
> the need to aggregate on a string, by creating an array while doing a group
> by? Should I manipulate my data to be able to do it, maybe by generating an
> int out of those strings? Any other idea?
>
> Well, array_agg is non-parallel too, so don't see how having an array
> and converting that into a string later would help.  The other
> aggregates that are parallel aware don't really let you get individual
> values back out of the aggregated state, so there's not really a way
> to turn that into an array or a string containing all the values that
> were aggregated.
>
> Does your use-case really need parallel versions of these aggregates?
> I imagined that these would perform best when the underlying scan had
> to skip lots of values, or when the aggregate had a FILTER (WHERE ...)
> clause. Maybe if the filtering can be done by using an index then
> performance would up to the level you need?
>
> If you could share a simplified version of your use case perhaps
> someone can suggest a way to speed it up another way.
>
> --
>  David Rowley                   http://www.2ndQuadrant.com/
>  PostgreSQL Development, 24x7 Support, Training & Services
>