This question arises as a result and the result of an SQL function is very slow compared to a query without a function wrapper . I should note that I do not consider this a duplicate, since this issue requires a solution to a specific problem. I ask for additional information about the behavior in general here and to demonstrate how it can be reproduced. (To demonstrate the difference, you can see a rather long stream of comments in the accepted answer, where we discussed the behavior, and I felt it was out of topic, especially considering the length.)
I have a function. Here's a sample demonstrating the behavior of interest:
CREATE OR REPLACE FUNCTION test(INT) RETURNS TABLE(num INT, letter TEXT) VOLATILE LANGUAGE SQL AS $$ SELECT * FROM (VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')) x LIMIT $1 $$;
When I run this EXPLAIN :
EXPLAIN ANALYZE SELECT * FROM test(10);
I get this result in psql (where I removed the giant "Query Plan" header):
Function Scan on test (cost=0.25..10.25 rows=1000 width=36) (actual time=0.125..0.136 rows=5 loops=1) Total runtime: 0.179 ms (2 rows)
Pay attention to the line rating. It evaluates 1000 lines.
But if I change the function to STABLE or IMMUTABLE :
CREATE OR REPLACE FUNCTION test(INT) RETURNS TABLE(num INT, letter TEXT) STABLE LANGUAGE SQL AS $$ SELECT * FROM (VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')) x LIMIT $1 $$;
Then the same EXPLAIN gives me a different plan:
Limit (cost=0.00..0.06 rows=5 width=36) (actual time=0.010..0.050 rows=5 loops=1) -> Values Scan on "*VALUES*" (cost=0.00..0.06 rows=5 width=36) (actual time=0.005..0.018 rows=5 loops=1) Total runtime: 0.087 ms (3 rows)
Now it correctly evaluates 5 lines and shows the plan of the request contained within the function. Cost is much higher. Lead time also decreased. (The request is so short that it may not be particularly significant.)
In light of the related question regarding a much larger amount of data and having a very significant difference in performance, it would seem that the scheduler really does something different depending on whether the function is VOLATILE or STABLE / IMMUTABLE .
What exactly does this planner do, and where can I read the documentation on it?
These tests were performed in PG 9.3.