Re: Performance degradation with non-null proconfig

From: Simon Riggs <simon(at)2ndquadrant(dot)com>
To: Alastair McKinley <a(dot)mckinley(at)analyticsengines(dot)com>
Cc: "pgsql-general(at)lists(dot)postgresql(dot)org" <pgsql-general(at)lists(dot)postgresql(dot)org>
Subject: Re: Performance degradation with non-null proconfig
Date: 2020-11-19 11:24:08
Message-ID: CANP8+jKMGC_AwaEr=cuRaBKwskUuB0ErFDHJA2KnAGmHt4rk5A@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On Thu, 19 Nov 2020 at 09:10, Alastair McKinley
<a(dot)mckinley(at)analyticsengines(dot)com> wrote:
>
> Hi all,
>
> I recently came across a subtle performance issue when working with some compiled UDFs to optimise a workload.
>
> These UDFs accidently had "set search_path = 'public'" in their definition. When profiling with perf, I noticed a large amount of elapsed time spent in the function
>
> voidAtEOXact_GUC(bool isCommit, int nestLevel)
>
> Reading the comments it is called when exiting a function with a custom proconfig, removing it for my case gave me a very large (3x) speedup.
>
> Below is a contrived test case that illustrates this issue (tested on 13.0, but also seen in 12.4).
>
> create table test as
> select r as row_id,
> array_agg(random()::float4) as data
> from generate_series(1,100000) r,
> generate_series(1,20) e
> group by r;
>
> create or replace function array_sum(float4[]) returns float4 as
> $$
> select sum(e) from unnest($1) e;
> $$ language sql immutable parallel safe;
>
>
> create or replace function array_sum_public_search_path(float4[]) returns float4 as
> $$
> select sum(e) from unnest($1) e;
> $$ language sql immutable parallel safe set search_path = 'public';
>
> \timing on
> \o /dev/null
> select format($q$ explain (analyze,verbose,buffers) select array_sum(data) from test $q$) from generate_series(1,10);
> \gexec
> select format($q$ explain (analyze,verbose,buffers) select array_sum_public_search_path(data) from test $q$) from generate_series(1,10);
> \gexec
>
>
> Test output:
>
> postgres=# select format($q$ explain (analyze,verbose,buffers) select array_sum(data) from test $q$) from generate_series(1,10);
> Time: 0.940 ms
> postgres=# \gexec
> Time: 745.988 ms
> Time: 677.056 ms
> Time: 653.709 ms
> Time: 651.033 ms
> Time: 650.063 ms
> Time: 647.741 ms
> Time: 650.328 ms
> Time: 651.954 ms
> Time: 655.384 ms
> Time: 650.988 ms
> Time: 0.976 ms
> postgres=# select format($q$ explain (analyze,verbose,buffers) select array_sum_public_search_path(data) from test $q$) from generate_series(1,10);
> Time: 0.774 ms
> postgres=# \gexec
> Time: 871.628 ms
> Time: 853.298 ms
> Time: 856.798 ms
> Time: 857.794 ms
> Time: 861.836 ms
> Time: 858.291 ms
> Time: 861.763 ms
> Time: 850.221 ms
> Time: 851.470 ms
> Time: 858.875 ms
> Time: 1.514 ms
> postgres=#
>
>
>
> I didn't see this discussed anywhere else, it might be worth adding a note to the documentation if it can't easily be addressed.

I came up with a simpler test, which doesn't reproduce this

postgres=# create or replace function proconfig1() returns integer
language sql as $$ select 1; $$;
CREATE FUNCTION
postgres=# create or replace function proconfig2() returns integer
language sql as $$ select 1; $$ set search_path = 'public';
CREATE FUNCTION
postgres=# \timing
Timing is on.
postgres=# select sum(proconfig1()) from generate_series(1,10000);
sum
-------
10000
(1 row)
Time: 2.818 ms
postgres=# select sum(proconfig2()) from generate_series(1,10000);
sum
-------
10000
(1 row)
Time: 41.750 ms

So the overhead would be 4us per call? Other tests show that is
roughly the same situation for PLpgSQL functions.

Can't see anything to document as yet.

--
Simon Riggs http://www.EnterpriseDB.com/

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Muthukumar.GK 2020-11-19 12:04:16 Multiple result set not working
Previous Message Paul Förster 2020-11-19 10:17:59 Re: \COPY command and indexes in tables