9

我们写了一个函数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 以在数据库记录的创建和修改字段中输入或编辑值。但是,我们发现在连续添加或更新记录时它返回相同的值。

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

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

我猜正在发生的事情是正在评估此函数并且正在缓存结果以进行优化,因为它被标记为 IMMUTABLE 指示 Postgres 引擎在给定相同(空)参数列表的情况下返回值不应更改。但是,当不在触发器中使用时,当直接在 INSERT 语句中使用时,该函数将返回一个不同的值五次,然后从那时起返回相同的值。这是由于某些优化算法说“如果在会话中使用 IMMUTABLE 函数超过 5 次,则缓存结果以供将来调用”之类的内容吗?

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

(对于希望查询当前命令修改的行的 AFTER 触发器是不合适的。)

但我并不完全清楚为什么。

4

1 回答 1

9

pgAdmin 或 Postgres 永远不会自动IMMUTABLE添加关键字。创建或替换该功能的人就是这样做的。

给定函数的正确波动率VOLATILE是(也是默认值),不是STABLE- 或者使用clock_timestamp()which is VOLATILEin contrast now()or CURRENT_TIMESTAMPwhich are没有意义STABLE:它们在同一事务中返回相同的时间戳。手册:

clock_timestamp()返回实际的当前时间,因此即使在单个 SQL 命令中,它的值也会发生变化。

手册警告说,功能波动STABLE...

不适用于AFTER希望查询当前命令修改的行的触发器。

..因为触发函数的重复评估可以为同一行返回不同的结果。所以,不是STABLE

你问:

您是否知道为什么函数在设置为时坚持第五个值之前正确返回了五次IMMUTABLE

Postgres维基:

在 9.2 中,计划程序将使用与发送的参数有关的特定计划(查询将在执行时进行计划),除非查询被执行多次并且计划程序确定通用计划不会比特定计划贵太多.

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

在旁边

trunc()比这里稍微快一点floor()并且做同样的事情,因为保证了正数:

SELECT (trunc(EXTRACT(EPOCH FROM clock_timestamp()) * 10) - 13885344000)::int
于 2015-02-18T00:20:17.360 回答