postgres COALESCE 是懒惰的吗?

Is postgres COALESCE lazy?

如果我有这样的查询:

SELECT COALESCE(
  (SELECT value FROM precomputed WHERE ...),
  alwaysComputeValue(...)
);

第二个表达式会被计算吗? 这也取决于执行计划者还是独立的?

来自the documentation

Like a CASE expression, COALESCE only evaluates the arguments that are needed to determine the result; that is, arguments to the right of the first non-null argument are not evaluated.

概念上是懒惰的:

Like a CASE expression, COALESCE only evaluates the arguments that are needed to determine the result; that is, arguments to the right of the first non-null argument are not evaluated.

https://www.postgresql.org/docs/9.6/static/functions-conditional.html

但是,如果右边的表达式不是易变的,那么它是否惰性应该没有区别,所以在这种情况下,查询规划器可以允许急切地计算右边的参数如果它是稳定的或不可变的,如果这看起来是一个明智的优化。

一个明显的例子是 SELECT COALESCE(a, b) FROM table 它可能会检索所有行的 ab 字段,而不是检索 a 然后检索 b 如有必要。

关于在这里产生任何可观察效果的唯一方法是,如果您编写了一个可变函数并故意将其错误标记为 stableimmutable。那么 可能 如果它在 coalesce 的右侧,而左侧不为空,则它会被评估。 (当然,一个真正稳定的函数也是可能的,但如果它是稳定的,它就没有副作用,如果它没有副作用,它是否发生就不会被观察到)。

给定:

CREATE OR REPLACE FUNCTION immutable_func(arg integer)
RETURNS integer
AS $BODY$
BEGIN
    RAISE NOTICE 'Immutable function called with %', arg;
    RETURN arg;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;

WITH data AS
(
    SELECT 10 AS num
    UNION ALL SELECT 5
    UNION ALL SELECT 20
)
select coalesce(num, immutable_func(2))
from data

规划器知道它会对每一行的 immutable_func(2) 产生相同的结果,并在整个查询中调用它一次,给我们消息 Immutable function called with 2。所以它确实被评估了,即使它不在"arguments to the right of the first non-null argument are not evaluated"的规则之内。回报是,在(合理预期)多个 null num 的情况下,它仍然只有一次 运行。

这与记录在案的行为的字面意思相悖是可以的,因为我们已经告诉它这样的优化是有效的。如果这导致了问题,错误将是将函数标记为 IMMUTABLE 而不是在急切的评估中。

也可以是中途。使用 SELECT COALESCE(a, Some_Func(b)) FROM table 它不会急切地评估 Some_Func(b),但它会检索 b 以便能够这样做。

只要它实际影响(非作弊)可观察到的行为,就会遵守规则。