| From: | Chris Campbell <chris(at)bignerdranch(dot)com> | 
|---|---|
| To: | PostgreSQL Bugs List <pgsql-bugs(at)postgresql(dot)org>, Don Marco <mark(at)bignerdranch(dot)com>, Aaron Hillegass <aaron(at)bignerdranch(dot)com> | 
| Subject: | Function is called multiple times in subselect | 
| Date: | 2004-03-12 01:29:10 | 
| Message-ID: | 40511266.7050009@bignerdranch.com | 
| Views: | Whole Thread | Raw Message | Download mbox | Resend email | 
| Thread: | |
| Lists: | pgsql-bugs | 
pgsql-bugs:
I wrote a plpgsql function that does a fairly expensive calculation on 
its input, and want to peform a query that:
1. Selects certain rows from a table, then
2. Calls my function on the selected rows
So I wrote a query and used a subselect to first select the rows, and 
then used the outer select to call my function on each of the selected 
rows and return the result.
I referenced the result of my inner select's calculation multiple times 
in the outer select, and found that my function is called once for *each 
reference* to its result in the outer select, rather than once for each 
row of the inner select.
Here's a simple example:
     CREATE FUNCTION square_it(INTEGER) RETURNS INTEGER AS '
     DECLARE
        i ALIAS FOR $1;
     BEGIN
        RAISE NOTICE ''square_it(%)'', i;
        RETURN (i * i);
     END;
     ' LANGUAGE 'plpgsql';
CREATE TABLE foo (i INTEGER);
     INSERT INTO foo (i) VALUES (1);
     INSERT INTO foo (i) VALUES (2);
     INSERT INTO foo (i) VALUES (3);
     INSERT INTO foo (i) VALUES (4);
     SELECT query.i,
            query.squared AS test1,
            query.squared + 1 AS test2,
            query.squared + 2 AS test3,
            query.squared + 3 AS test4
     FROM (
         SELECT i,
                square_it(i) AS squared
         FROM foo
     ) query;
When I run it, I expect to see 4 lines of output, and I expect that 
square_it() will have been called 4 times (once for each row). However, 
it is actually called *4 times for each row* because I reference 
"query.squared" 4 times in the outer select.
     NOTICE:  square_it(1)
     NOTICE:  square_it(1)
     NOTICE:  square_it(1)
     NOTICE:  square_it(1)
     NOTICE:  square_it(2)
     NOTICE:  square_it(2)
     NOTICE:  square_it(2)
     NOTICE:  square_it(2)
     NOTICE:  square_it(3)
     NOTICE:  square_it(3)
     NOTICE:  square_it(3)
     NOTICE:  square_it(3)
     NOTICE:  square_it(4)
     NOTICE:  square_it(4)
     NOTICE:  square_it(4)
     NOTICE:  square_it(4)
      i | test1 | test2 | test3 | test4
     ---+-------+-------+-------+-------
      1 |     1 |     2 |     3 |     4
      2 |     4 |     5 |     6 |     7
      3 |     9 |    10 |    11 |    12
      4 |    16 |    17 |    18 |    19
     (4 rows)
I don't think this should be happening (PostgreSQL 7.4.1). I think it 
should be saving the result of the calculation in the resulting rows 
from the innery query. In my case, that means my query takes 4 times 
longer than it should. And when it's a query that takes a nontrivial 
amount of time to execute, that's harsh. Any ideas?
Here's the query plan:
QUERY PLAN
-------------------------------------------------------------------------------------------------
  Seq Scan on foo  (cost=0.00..37.50 rows=1000 width=4) (actual 
time=3.203..4.384 rows=4 loops=1)
  Total runtime: 4.742 ms
Thanks!
- Chris
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Tom Lane | 2004-03-12 04:02:21 | Re: Function is called multiple times in subselect | 
| Previous Message | Tom Lane | 2004-03-11 23:41:06 | Re: BUG #1096: pg_restore cannot restore large objects with other oid columns |