IMMUTABLE、STABLE 和 VOLATILE 关键字如何影响函数的行为?

How do IMMUTABLE, STABLE and VOLATILE keywords effect behaviour of function?

我们写了一个函数 get_timestamp() 定义为

CREATE OR REPLACE FUNCTION get_timestamp()
  RETURNS integer AS
$$
SELECT (FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 10) - 13885344000)::int;
$$
LANGUAGE SQL;

这用于 INSERT 和 UPDATE 以在数据库记录中创建和修改的字段中输入或编辑值。但是,我们发现在连续添加或更新记录时,它是 returning 相同的值。

在检查 pgAdmin III 中的函数时,我们注意到在 运行 上 SQL 构建函数时,在 LANGUAGE SQL 语句之后注入了关键字 IMMUTABLE。 documentation 声明默认值是 VOLATILE(如果出现 none,VOLATILE 是默认假设)所以我不确定为什么注入 IMMUTABLE,但是,将其更改为 STABLE 解决了问题重复值。

注意:如已接受的答案中所述,pgAdmin 或 Postgres 永远不会将 IMMUTABLE 添加到函数中,并且必须在开发过程中添加。

我猜正在发生的事情是正在评估此函数并且正在缓存结果以进行优化,因为它被标记为 IMMUTABLE 指示 Postgres 引擎 return 值不应更改给定相同的(空的)参数列表。但是,当不在触发器中使用时,当直接在 INSERT 语句中使用时,该函数将 return 一个不同的值五次,然后 return 从那时起使用相同的值。这是由于某些优化算法说的 "If an IMMUTABLE function is used more that 5 times in a session, cache the result for future calls" 吗?

如能说明如何在 Postgres 函数中使用这些关键字,我们将不胜感激。考虑到我们在触发器中使用此函数,STABLE 对我们来说是正确的选择吗?还是有更多需要考虑的东西,例如文档说:

(It is inappropriate for AFTER triggers that wish to query rows modified by the current command.)

但我不是很清楚为什么。

关键字 IMMUTABLE never 由 pgAdmin 或 Postgres 自动添加。谁创建或替换了该函数。

正确的volatility for the given function is VOLATILE (also the default), not STABLE - or it wouldn't make sense to use clock_timestamp() which is VOLATILE in contrast to now() or CURRENT_TIMESTAMP which are STABLE: those return the same timestamp within the same transaction. The manual:

clock_timestamp() returns the actual current time, and therefore its value changes even within a single SQL command.

波动率函数manual warns STABLE ...

is inappropriate for AFTER triggers that wish to query rows modified by the current command.

.. 因为对触发器函数的重复计算可能会对同一行产生 return 不同的 结果。所以,不是 STABLE.

你问:

Do you have an idea as to why the function returned correctly five times before sticking on the fifth value when set as IMMUTABLE?

Postgres Wiki:

With 9.2, the planner will use specific plans regarding to the parameters sent (the query will be planned at execution), except if the query is executed several times and the planner decides that the generic plan is not too much more expensive than the specific plans.

大胆强调我的。对于没有输入参数的 IMMUTABLE 函数似乎没有意义。但是假标签被正文中的 VOLATILE 函数覆盖(voids function inlining):不同的查询计划仍然有意义。 相关:

放在一边

trunc()floor() 稍微快一点,这里也一样,因为可以保证正数:

SELECT (trunc(EXTRACT(EPOCH FROM clock_timestamp()) * 10) - 13885344000)::int