Reputation: 126477
According to PostgreSQL: Documentation: 38.7. Function Volatility Categories:
A STABLE function cannot modify the database and is guaranteed to return the same results given the same arguments for all rows within a single statement. This category allows the optimizer to optimize multiple calls of the function to a single call.
What about when using CTEs? If I call a STABLE
function inside a CTE and then again inside the primary SELECT
query, will the optimizer optimize both calls of the function to a single call?
How can you tell? (I don't know how to use EXPLAIN
.)
In the impractical example below, I want to make sure that the function get_user_by_id()
is only called once.
CREATE TABLE users (
id bigserial PRIMARY KEY,
username varchar(64) NOT NULL
);
CREATE FUNCTION get_user_by_id(_id bigint) RETURNS users AS $$
SELECT *
FROM users
WHERE id = _id
$$ LANGUAGE SQL STABLE;
INSERT INTO users (username) VALUES ('user1');
WITH error AS (
SELECT -1 AS code
WHERE (SELECT get_user_by_id(3) IS NULL)
)
SELECT code AS id, NULL AS username FROM error
UNION ALL
SELECT * FROM get_user_by_id(3) WHERE id IS NOT NULL;
Upvotes: 0
Views: 74
Reputation: 126477
I think the answer is no, multiple calls to a STABLE function are not optimized across CTEs. I don't know how to prove it, but according to PostgreSQL: Documentation: 11: 7.8. WITH Queries (Common Table Expressions), CTEs seem to be separate "auxiliary statements". And, they don't seem to be well-integrated with the parent query. For example:
. . . the optimizer is less able to push restrictions from the parent query down into a WITH query than an ordinary subquery. The WITH query will generally be evaluated as written, without suppression of rows that the parent query might discard afterwards.
Upvotes: 0