Ășt 18. 2. 2020 v 6:03 odesĂ­latel Amit Langote <amitlangot...@gmail.com>
napsal:

> Hi,
>
> On Sun, Feb 16, 2020 at 11:13 PM Pavel Stehule <pavel.steh...@gmail.com>
> wrote:
> > when I do some profiling of plpgsql, usually I surprised how significant
> overhead has expression execution. Any calculations are very slow.
> >
> > This is not typical example of plpgsql, but it shows cleanly where is a
> overhead
> >
> > CREATE OR REPLACE FUNCTION public.foo()
> >  RETURNS void
> >  LANGUAGE plpgsql
> >  IMMUTABLE
> > AS $function$
> > declare i bigint = 0;
> > begin
> >   while i < 100000000
> >   loop
> >     i := i + 1;
> >   end loop;
> > end;
> > $function$
> >
> > Profile of development  version
> >
> >   10,04%  plpgsql.so                          [.] exec_eval_simple_expr
> >    9,17%  postgres                            [.] AcquireExecutorLocks
> >    7,01%  postgres                            [.] ExecInterpExpr
> >    5,86%  postgres                            [.]
> OverrideSearchPathMatchesCurrent
> >    4,71%  postgres                            [.] GetCachedPlan
> >    4,14%  postgres                            [.] AcquirePlannerLocks
> >    3,72%  postgres                            [.] RevalidateCachedQuery
> >    3,56%  postgres                            [.] MemoryContextReset
> >    3,43%  plpgsql.so                          [.] plpgsql_param_eval_var
>
> I was thinking about this overhead many months back and had even
> written a patch to avoid going to the planner for "simple"
> expressions, which can be handled by the executor.  Here is what the
> performance looks like:
>
> HEAD:
>
> latency: 31979.393 ms
>
>     18.32%  postgres  postgres           [.] ExecInterpExpr
>     11.37%  postgres  plpgsql.so         [.] exec_eval_expr
>      8.58%  postgres  plpgsql.so         [.] plpgsql_param_eval_var
>      8.31%  postgres  plpgsql.so         [.] exec_stmt
>      6.44%  postgres  postgres           [.] GetCachedPlan
>      5.47%  postgres  postgres           [.] AcquireExecutorLocks
>      5.30%  postgres  postgres           [.] RevalidateCachedQuery
>      4.79%  postgres  plpgsql.so         [.] exec_assign_value
>      4.41%  postgres  postgres           [.] SPI_plan_get_cached_plan
>      4.36%  postgres  postgres           [.] MemoryContextReset
>      4.22%  postgres  postgres           [.] ReleaseCachedPlan
>      4.03%  postgres  postgres           [.]
> OverrideSearchPathMatchesCurrent
>      2.63%  postgres  plpgsql.so         [.] exec_assign_expr
>      2.11%  postgres  postgres           [.] int84lt
>      1.95%  postgres  postgres           [.]
> ResourceOwnerForgetPlanCacheRef
>      1.71%  postgres  postgres           [.] int84pl
>      1.57%  postgres  postgres           [.]
> ResourceOwnerRememberPlanCacheRef
>      1.38%  postgres  postgres           [.] recomputeNamespacePath
>      1.35%  postgres  postgres           [.] ScanQueryForLocks
>      1.24%  postgres  plpgsql.so         [.] exec_cast_value
>      0.38%  postgres  postgres           [.]
> ResourceOwnerEnlargePlanCacheRefs
>      0.05%  postgres  [kernel.kallsyms]  [k] __do_softirq
>      0.03%  postgres  postgres           [.] GetUserId
>
> Patched:
>
> latency: 21011.871 ms
>
>     28.26%  postgres  postgres           [.] ExecInterpExpr
>     12.26%  postgres  plpgsql.so         [.] plpgsql_param_eval_var
>     12.02%  postgres  plpgsql.so         [.] exec_stmt
>     11.10%  postgres  plpgsql.so         [.] exec_eval_expr
>     10.05%  postgres  postgres           [.] SPI_plan_is_valid
>      7.09%  postgres  postgres           [.] MemoryContextReset
>      6.65%  postgres  plpgsql.so         [.] exec_assign_value
>      3.53%  postgres  plpgsql.so         [.] exec_assign_expr
>      2.91%  postgres  postgres           [.] int84lt
>      2.61%  postgres  postgres           [.] int84pl
>      2.42%  postgres  plpgsql.so         [.] exec_cast_value
>      0.86%  postgres  postgres           [.] CachedPlanIsValid
>      0.16%  postgres  plpgsql.so         [.] SPI_plan_is_valid@plt
>      0.05%  postgres  [kernel.kallsyms]  [k] __do_softirq
>      0.03%  postgres  [kernel.kallsyms]  [k] finish_task_switch
>
> I didn't send the patch, because it didn't handle the cases where a
> simple expression consists of an inline-able function(s) in it, which
> are better handled by a full-fledged planner call backed up by the
> plan cache.  If we don't do that then every evaluation of such
> "simple" expression needs to invoke the planner.  For example:
>
> Consider this inline-able SQL function:
>
> create or replace function sql_incr(a bigint)
> returns int
> immutable language sql as $$
> select a+1;
> $$;
>
> Then this revised body of your function foo():
>
> CREATE OR REPLACE FUNCTION public.foo()
>  RETURNS int
>  LANGUAGE plpgsql
>  IMMUTABLE
> AS $function$
> declare i bigint = 0;
> begin
>   while i < 1000000
>   loop
>     i := sql_incr(i);
>   end loop; return i;
> end;
> $function$
> ;
>
> With HEAD `select foo()` finishes in 786 ms, whereas with the patch,
> it takes 5102 ms.
>
> I think the patch might be good idea to reduce the time to compute
> simple expressions in plpgsql, if we can address the above issue.
>

Your patch is very interesting - minimally it returns performance before
8.2. The mentioned issue can be fixed if we disallow SQL functions in this
fast execution.

I am worried about too low percent if this fundament methods.

     2.91%  postgres  postgres           [.] int84lt
     2.61%  postgres  postgres           [.] int84pl

Perl

  18,20%  libperl.so.5.30.1                        [.] Perl_pp_add
  17,61%  libperl.so.5.30.1                        [.] Perl_pp_lt

So can be nice if we increase percent overhead over 10%, maybe more.

Maybe we can check if expression has only builtin immutable functions, and
if it, then we can reuse expression state

More, if I understand well, the function is running under snapshot, so
there is not possibility to plan invalidation inside function. So some
checks should not be repeated.

Pavel


> Thanks,
> Amit
>

Reply via email to