Обсуждение: Using functions as filters in queries

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

Using functions as filters in queries

От
Chris Mungall
Дата:
I have a problem that can be reduced to this equivalent but simpler
problem:

Case 1:

CREATE TABLE t (
    n int,
    x varchar(32)
);
CREATE INDEX ti ON t(n);
CREATE INDEX tx ON t(x);
<insert 100k rows of data, random words into x>
VACUUM ANALYZE;
EXPLAIN ANALYZE select * from t where n=5 AND x like 'a%';

 Index Scan using ti on t  (cost=0.00..3.02 rows=1 width=15) (actual
time=0.12..0.12 rows=0 loops=1)
   Index Cond: (n = 5)
   Filter: (x ~~ 'a%'::text)
 Total runtime: 0.16 msec

This is perfect - ti is used for indexing.

Case 2:

Now I want to replace the "n=5" clause with a function:

CREATE FUNCTION f(t, int) RETURNS bool AS
 'SELECT $1.n = $2'
LANGUAGE 'sql';

EXPLAIN ANALYZE select * from t where f(t, 5) AND x like 'a%';

 Seq Scan on t  (cost=0.00..1161.25 rows=436 width=15) (actual
time=265.04..265.04 rows=0 loops=1)
   Filter: (f(t.*, 5) AND (x ~~ 'a%'::text))
 Total runtime: 265.08 msec

If I set enable_seqscan=0, I get this:

 Seq Scan on t  (cost=0.00..1161.25 rows=436 width=15) (actual
time=262.45..262.45 rows=0 loops=1)
   Filter: (f(t.*, 5) AND (x ~~ 'a%'::text))
 Total runtime: 262.49 msec

Same thing.

Now looking at the two cases (without and with function) I can see that
they are equivalent, but Pg treats them differently. I guess it is failing
to distiguish between two cases - if the function has no FROM clause, then
it is a simple case of variable substitution into the original WHERE
clause. If it does include a FROM clause, it's not so simple and
optimisation is hard, so the function becomes the filter.

I notice that internal functions (eg @ on boxes/points) are not treated
this way. is there any way to get my function treated like an internal
function, or is not as simple as that?

You could argue that my function is pointless and I could simply do the
replacement in the application layer that calls the SQL. This is true, but
with my full example I would like to hide some aspects of the physical
layer behind a nice SQL/function logical layer.


Re: Using functions as filters in queries

От
Stephan Szabo
Дата:
On Mon, 10 Mar 2003, Chris Mungall wrote:

> I have a problem that can be reduced to this equivalent but simpler
> problem:

> EXPLAIN ANALYZE select * from t where n=5 AND x like 'a%';

5 is a constant.

> Case 2:
>
> Now I want to replace the "n=5" clause with a function:
>
> CREATE FUNCTION f(t, int) RETURNS bool AS
>  'SELECT $1.n = $2'
> LANGUAGE 'sql';
>
> EXPLAIN ANALYZE select * from t where f(t, 5) AND x like 'a%';
>
> Now looking at the two cases (without and with function) I can see that
> they are equivalent, but Pg treats them differently. I guess it is failing
> to distiguish between two cases - if the function has no FROM clause, then
> it is a simple case of variable substitution into the original WHERE
> clause. If it does include a FROM clause, it's not so simple and
> optimisation is hard, so the function becomes the filter.

It doesn't look at the contents of the function.  It looks at whether the
function is defined IMMUTABLE, STABLE or VOLATILE.  With a VOLATILE
function (the default), the system is not guaranteed that given the
same arguments that the result is the same.  You might want to read
the description in the manpage for CREATE FUNCTION.




Re: Using functions as filters in queries

От
Stephan Szabo
Дата:
On Wed, 12 Mar 2003, Stephan Szabo wrote:

>
> On Mon, 10 Mar 2003, Chris Mungall wrote:
>
> > I have a problem that can be reduced to this equivalent but simpler
> > problem:
>
> > EXPLAIN ANALYZE select * from t where n=5 AND x like 'a%';
>
> 5 is a constant.
>
> > Case 2:
> >
> > Now I want to replace the "n=5" clause with a function:
> >
> > CREATE FUNCTION f(t, int) RETURNS bool AS
> >  'SELECT $1.n = $2'
> > LANGUAGE 'sql';
> >
> > EXPLAIN ANALYZE select * from t where f(t, 5) AND x like 'a%';
> >
> > Now looking at the two cases (without and with function) I can see that
> > they are equivalent, but Pg treats them differently. I guess it is failing
> > to distiguish between two cases - if the function has no FROM clause, then
> > it is a simple case of variable substitution into the original WHERE
> > clause. If it does include a FROM clause, it's not so simple and
> > optimisation is hard, so the function becomes the filter.
>
> It doesn't look at the contents of the function.  It looks at whether the
> function is defined IMMUTABLE, STABLE or VOLATILE.  With a VOLATILE
> function (the default), the system is not guaranteed that given the
> same arguments that the result is the same.  You might want to read
> the description in the manpage for CREATE FUNCTION.

Of course, I misread what explain did (without trying the
enable_seqscan=off case) and this is still not indexable because even
after that, you'll not get a clause on the outside that it considers
indexable.  It is smart enough (7.4 anyway) to make the filter ((t.*).n)=5
which I thought it'd index, but doesn't. :(


Re: Using functions as filters in queries

От
Xue-Feng Yang
Дата:
Could you please stop to send these message?


 --- Stephan Szabo <sszabo@megazone23.bigpanda.com>
wrote: >
> On Mon, 10 Mar 2003, Chris Mungall wrote:
>
> > I have a problem that can be reduced to this
> equivalent but simpler
> > problem:
>
> > EXPLAIN ANALYZE select * from t where n=5 AND x
> like 'a%';
>
> 5 is a constant.
>
> > Case 2:
> >
> > Now I want to replace the "n=5" clause with a
> function:
> >
> > CREATE FUNCTION f(t, int) RETURNS bool AS
> >  'SELECT $1.n = $2'
> > LANGUAGE 'sql';
> >
> > EXPLAIN ANALYZE select * from t where f(t, 5) AND
> x like 'a%';
> >
> > Now looking at the two cases (without and with
> function) I can see that
> > they are equivalent, but Pg treats them
> differently. I guess it is failing
> > to distiguish between two cases - if the function
> has no FROM clause, then
> > it is a simple case of variable substitution into
> the original WHERE
> > clause. If it does include a FROM clause, it's not
> so simple and
> > optimisation is hard, so the function becomes the
> filter.
>
> It doesn't look at the contents of the function.  It
> looks at whether the
> function is defined IMMUTABLE, STABLE or VOLATILE.
> With a VOLATILE
> function (the default), the system is not guaranteed
> that given the
> same arguments that the result is the same.  You
> might want to read
> the description in the manpage for CREATE FUNCTION.
>
>
>
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster

______________________________________________________________________
Post your free ad now! http://personals.yahoo.ca

flood of messages (was: Re: Using functions as filters in queries)

От
"Stephane Charette"
Дата:
On Wed, 12 Mar 2003 17:24:49 -0500 (EST), Xue-Feng Yang wrote:

>Could you please stop to send these message?

Yes!  Please!  How did this flood of messages start a few days ago???
This is getting quite annoying.

Stéphane


Could you please stop to send these message?

От
Xue-Feng Yang
Дата:
Could you please stop to send these message?

I unscripted this list a few months ago and hadn't
received messages for months.

I received messages from the list again started from
yesterday.

Could you please stop to send these message?

 --- Xue-Feng Yang <just4look@yahoo.com> wrote: >
Could you please stop to send these message?
>
>
>  --- Stephan Szabo <sszabo@megazone23.bigpanda.com>
> wrote: >
> > On Mon, 10 Mar 2003, Chris Mungall wrote:
> >
> > > I have a problem that can be reduced to this
> > equivalent but simpler
> > > problem:
> >
> > > EXPLAIN ANALYZE select * from t where n=5 AND x
> > like 'a%';
> >
> > 5 is a constant.
> >
> > > Case 2:
> > >
> > > Now I want to replace the "n=5" clause with a
> > function:
> > >
> > > CREATE FUNCTION f(t, int) RETURNS bool AS
> > >  'SELECT $1.n = $2'
> > > LANGUAGE 'sql';
> > >
> > > EXPLAIN ANALYZE select * from t where f(t, 5)
> AND
> > x like 'a%';
> > >
> > > Now looking at the two cases (without and with
> > function) I can see that
> > > they are equivalent, but Pg treats them
> > differently. I guess it is failing
> > > to distiguish between two cases - if the
> function
> > has no FROM clause, then
> > > it is a simple case of variable substitution
> into
> > the original WHERE
> > > clause. If it does include a FROM clause, it's
> not
> > so simple and
> > > optimisation is hard, so the function becomes
> the
> > filter.
> >
> > It doesn't look at the contents of the function.
> It
> > looks at whether the
> > function is defined IMMUTABLE, STABLE or VOLATILE.
>
> > With a VOLATILE
> > function (the default), the system is not
> guaranteed
> > that given the
> > same arguments that the result is the same.  You
> > might want to read
> > the description in the manpage for CREATE
> FUNCTION.
> >
> >
> >
> >
> > ---------------------------(end of
> > broadcast)---------------------------
> > TIP 4: Don't 'kill -9' the postmaster
>
>
______________________________________________________________________
>
> Post your free ad now! http://personals.yahoo.ca
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please
> send an appropriate
> subscribe-nomail command to majordomo@postgresql.org
> so that your
> message can get through to the mailing list cleanly

______________________________________________________________________
Post your free ad now! http://personals.yahoo.ca

Could you please stop to send these message?

От
Xue-Feng Yang
Дата:
Could you please stop to send these message?

I unscripted this list a few months ago and hadn't
received messages for months.

I received messages from the list again started from
yesterday.

Could you please stop to send these message?


 --- Xue-Feng Yang <just4look@yahoo.com> wrote: >
>
>
>  --- Stephan Szabo <sszabo@megazone23.bigpanda.com>
> wrote: >
> > On Mon, 10 Mar 2003, Chris Mungall wrote:
> >
> > > I have a problem that can be reduced to this
> > equivalent but simpler
> > > problem:
> >
> > > EXPLAIN ANALYZE select * from t where n=5 AND x
> > like 'a%';
> >
> > 5 is a constant.
> >
> > > Case 2:
> > >
> > > Now I want to replace the "n=5" clause with a
> > function:
> > >
> > > CREATE FUNCTION f(t, int) RETURNS bool AS
> > >  'SELECT $1.n = $2'
> > > LANGUAGE 'sql';
> > >
> > > EXPLAIN ANALYZE select * from t where f(t, 5)
> AND
> > x like 'a%';
> > >
> > > Now looking at the two cases (without and with
> > function) I can see that
> > > they are equivalent, but Pg treats them
> > differently. I guess it is failing
> > > to distiguish between two cases - if the
> function
> > has no FROM clause, then
> > > it is a simple case of variable substitution
> into
> > the original WHERE
> > > clause. If it does include a FROM clause, it's
> not
> > so simple and
> > > optimisation is hard, so the function becomes
> the
> > filter.
> >
> > It doesn't look at the contents of the function.
> It
> > looks at whether the
> > function is defined IMMUTABLE, STABLE or VOLATILE.
>
> > With a VOLATILE
> > function (the default), the system is not
> guaranteed
> > that given the
> > same arguments that the result is the same.  You
> > might want to read
> > the description in the manpage for CREATE
> FUNCTION.
> >
> >
> >
> >
> > ---------------------------(end of
> > broadcast)---------------------------
> > TIP 4: Don't 'kill -9' the postmaster
>
>
______________________________________________________________________
>
> Post your free ad now! http://personals.yahoo.ca
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please
> send an appropriate
> subscribe-nomail command to majordomo@postgresql.org
> so that your
> message can get through to the mailing list cleanly

______________________________________________________________________
Post your free ad now! http://personals.yahoo.ca

Could you please stop to send these message?

От
Xue-Feng Yang
Дата:
Could you please stop to send these message?

I unscripted this list a few months ago and hadn't
received messages for months.

I received messages from the list again started from
yesterday.

Could you please stop to send these message?

 --- Xue-Feng Yang <just4look@yahoo.com> wrote: > >
>
>  --- Stephan Szabo <sszabo@megazone23.bigpanda.com>
> wrote: >
> > On Mon, 10 Mar 2003, Chris Mungall wrote:
> >
> > > I have a problem that can be reduced to this
> > equivalent but simpler
> > > problem:
> >
> > > EXPLAIN ANALYZE select * from t where n=5 AND x
> > like 'a%';
> >
> > 5 is a constant.
> >
> > > Case 2:
> > >
> > > Now I want to replace the "n=5" clause with a
> > function:
> > >
> > > CREATE FUNCTION f(t, int) RETURNS bool AS
> > >  'SELECT $1.n = $2'
> > > LANGUAGE 'sql';
> > >
> > > EXPLAIN ANALYZE select * from t where f(t, 5)
> AND
> > x like 'a%';
> > >
> > > Now looking at the two cases (without and with
> > function) I can see that
> > > they are equivalent, but Pg treats them
> > differently. I guess it is failing
> > > to distiguish between two cases - if the
> function
> > has no FROM clause, then
> > > it is a simple case of variable substitution
> into
> > the original WHERE
> > > clause. If it does include a FROM clause, it's
> not
> > so simple and
> > > optimisation is hard, so the function becomes
> the
> > filter.
> >
> > It doesn't look at the contents of the function.
> It
> > looks at whether the
> > function is defined IMMUTABLE, STABLE or VOLATILE.
>
> > With a VOLATILE
> > function (the default), the system is not
> guaranteed
> > that given the
> > same arguments that the result is the same.  You
> > might want to read
> > the description in the manpage for CREATE
> FUNCTION.
> >
> >
> >
> >
> > ---------------------------(end of
> > broadcast)---------------------------
> > TIP 4: Don't 'kill -9' the postmaster
>
>
______________________________________________________________________
>
> Post your free ad now! http://personals.yahoo.ca
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please
> send an appropriate
> subscribe-nomail command to majordomo@postgresql.org
> so that your
> message can get through to the mailing list cleanly

______________________________________________________________________
Post your free ad now! http://personals.yahoo.ca

Re: Using functions as filters in queries

От
Tom Lane
Дата:
Stephan Szabo <sszabo@megazone23.bigpanda.com> writes:
> Of course, I misread what explain did (without trying the
> enable_seqscan=off case) and this is still not indexable because even
> after that, you'll not get a clause on the outside that it considers
> indexable.  It is smart enough (7.4 anyway) to make the filter ((t.*).n)=5
> which I thought it'd index, but doesn't. :(

Note that inline-expansion of SQL functions like this is new for 7.4;
it's not done in any current release.

I think the extra step to make this expression indexable is probably not
too hard: the constant-expression folder needs to be taught that
extracting a field from a whole-row Var can be replaced by a Var
reference to the field, ie, fold "(t.*).n" into "t.n".

            regards, tom lane

Re: Using functions as filters in queries

От
Stephan Szabo
Дата:
On Wed, 12 Mar 2003, Tom Lane wrote:

> Stephan Szabo <sszabo@megazone23.bigpanda.com> writes:
> > Of course, I misread what explain did (without trying the
> > enable_seqscan=off case) and this is still not indexable because even
> > after that, you'll not get a clause on the outside that it considers
> > indexable.  It is smart enough (7.4 anyway) to make the filter ((t.*).n)=5
> > which I thought it'd index, but doesn't. :(
>
> Note that inline-expansion of SQL functions like this is new for 7.4;
> it's not done in any current release.

I wasn't sure when it was added.

> I think the extra step to make this expression indexable is probably not
> too hard: the constant-expression folder needs to be taught that
> extracting a field from a whole-row Var can be replaced by a Var
> reference to the field, ie, fold "(t.*).n" into "t.n".

That's what I figured, but I wasn't sure if there was some case where it
was unsafe.


Re: Using functions as filters in queries

От
Tom Lane
Дата:
Stephan Szabo <sszabo@megazone23.bigpanda.com> writes:
> On Wed, 12 Mar 2003, Tom Lane wrote:
>> I think the extra step to make this expression indexable is probably not
>> too hard: the constant-expression folder needs to be taught that
>> extracting a field from a whole-row Var can be replaced by a Var
>> reference to the field, ie, fold "(t.*).n" into "t.n".

> That's what I figured, but I wasn't sure if there was some case where it
> was unsafe.

I haven't thought it through either, but this particular example seems
safe.

            regards, tom lane

Re: Using functions as filters in queries

От
Tom Lane
Дата:
Stephan Szabo <sszabo@megazone23.bigpanda.com> writes:
> Of course, I misread what explain did (without trying the
> enable_seqscan=off case) and this is still not indexable because even
> after that, you'll not get a clause on the outside that it considers
> indexable.  It is smart enough (7.4 anyway) to make the filter ((t.*).n)=5
> which I thought it'd index, but doesn't. :(

As of a few moments ago, CVS tip reduces that to t.n=5 which is
indexable.

regression=# EXPLAIN select * from t where f(t, 5) AND x like 'a%';
                          QUERY PLAN
--------------------------------------------------------------
 Index Scan using ti on t  (cost=0.00..17.08 rows=1 width=38)
   Index Cond: (n = 5)
   Filter: (x ~~ 'a%'::text)
(3 rows)


            regards, tom lane