数据库 – IMMUTABLE,STABLE和VOLATILE关键字如何影响函数的行为?

我们写了一个函数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来构建函数时,在LANGUAGE sql语句之后注入了关键字IMMUTABLE. documentation声明认值是VOLATILE(如果这些都没有出现,VOLATILE是认假设)所以我不确定为什么注入了IMMUTABLE,但是,将其更改为STABLE已经解决了重复值的问题.

注意:如接受的答案中所述,IMMUTABLE永远不会被pgAdmin或Postgres添加函数中,并且必须在开发期间添加.

我猜测正在发生的事情是这个函数正在被评估并且结果被缓存用于优化,因为它被标记为IMMUTABLE指示Postgres引擎在给定相同(空)参数列表的情况下返回值不应该改变.但是,当在触发器中未使用时,直接在INSERT语句中使用时,该函数将返回一个不同的值五次,然后再返回相同的值.这是由于某些优化算法会出现类似“如果在会话中多次使用IMMUTABLE函数5次,请将结果缓存以供将来调用”吗?

关于如何在Postgres函数中使用这些关键字的任何说明将不胜感激.对于我们来说STABLE是正确的选择,因为我们在触发器中使用了这个函数,或者还有更多要考虑的东西,例如文档说:

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

但我并不完全清楚原因.

解决方法

关键词IMMUTABLE永远不会被pgAdmin或Postgres自动添加.谁曾创建或替换过该功能.

给定函数的正确function volatility(读取手册)设置是VOLATILE,而不是STABLE – 或者使用clock_timestamp()是VOLATILE而不是now()CURRENT_TIMESTAMP没有意义,它们被定义为STABLE:那些返回相同的时间戳同一笔交易,per documentation

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.

..因为对同一行的触发函数的重复评估可以返回不同的结果.所以,不稳定.我不认为那里甚至需要警告,因为它很明显.

你问:

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函数仍会触发初始重新规划. (最后一点只是我的推测.)
这里有更多解释:

> PostgreSQL Stored Procedure Performance

在旁边

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

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

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 'EastRiver' 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...