[WIP] Caching constant stable expressions per execution

From: Marti Raudsepp <marti(at)juffo(dot)org>
To: pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: [WIP] Caching constant stable expressions per execution
Date: 2011-09-10 22:27:17
Message-ID: CABRT9RC-1wGxZC_Z5mwkdk70fgY2DRX3sLXzdP4voBKuKPZDow@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

This is a proof of concept patch for recognizing stable function calls
with constant arguments and only calling them once per execution. I'm
posting it to the list to gather feedback whether this is a dead end
or not.

Last time when this was brought up on the list, Tom Lane commented
that doing the checks for constant folding probably outweigh the
gains. http://archives.postgresql.org/pgsql-hackers/2010-11/msg01641.php

Yesterday I was looking at evaluate_function(), where currently
function constant folding happens, and realized that most of the
knowledge needed to implement this for FuncExpr and OpExpr (and
combinations thereof) is already there. This would probably cover 90%
of the use cases with very little overhead. Other expression types
can't be supported very well with this approach, notably case
expressions and AND/OR/NOT.

However, the code isn't very pretty. It works by changing
evaluate_function() to recognize stable/immutable functions with
constant stable/immutable arguments that aren't eligible for constant
folding. It sets a new boolean attribute FuncExpr.stableconst which is
checked during the function's first execution. If true, the result is
stored in ExprState and evalfunc is replaced with a new one that
returns the cached result.

Most common use cases cover timestamptz expressions (because they are
never immutable) such as:
ts>=to_timestamp('2010-01-01', 'YYYY-MM-DD')
ts>=(now() - interval '10 days')

Typically an index on the column would marginalize performance lost by
repeatedly evaluating the function.

----

Test data (1,051,777 rows, 38MB):
create table ts as select generate_series(timestamptz '2001-01-01',
'2011-01-01', '5min') ts;

Test query (using pgbench -T 30, taking the best of 3 runs):
select * from ts where ts>=to_timestamp('2001-01-01', 'YYYY-MM-DD')
and ts<=to_timestamp('2001-01-01', 'YYYY-MM-DD');

Unpatched tps = 0.927458
Patched tps = 6.729378

There's even a measurable improvement from caching now() calls:
select * from ts where ts>now();

Unpatched tps = 8.106439
Patched tps = 9.401684

Regards,
Marti

Attachment Content-Type Size
const-stable-expressions.patch text/x-patch 12.7 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Marti Raudsepp 2011-09-10 22:43:50 Re: [REVIEW] prepare plans of embedded sql on function start
Previous Message Tom Lane 2011-09-10 22:21:22 Re: [REVIEW] prepare plans of embedded sql on function start