Postgresql 中文操作指南

38.7. Function Volatility Categories #

每个函数都有一个 volatility 类别,其可能性是 VOLATILESTABLEIMMUTABLE 。如果 CREATE FUNCTION 命令没有指定一个类别,则 VOLATILE 是默认值。波动性类别是对优化器关于函数行为的承诺:

为了获得最佳优化结果,您应使用对其有效的最严格的可变性类别为函数进行标记。

任何具有副作用的函数 must 都必须标记为 VOLATILE,以便无法优化掉调用它的情况。即使某个函数没有副作用,如果其值在单个查询内可能会发生更改,也需要将其标记为 VOLATILE;其中一些示例包括 random()currval()timeofday()

另一个重要示例是 current_timestamp 函数族限定为 STABLE,因为它们的不在一个事务内更改。

考虑计划并且立即执行的简单交互式查询时,STABLEIMMUTABLE 类别之间的差异相对较小:函数是在计划期间执行一次还是在查询执行启动期间执行一次,这无关紧要。但是,如果计划被保存并且以后被重新使用,则差异就很大。当函数实际上不是 IMMUTABLE 时将其标记为 IMMUTABLE,可能允许它在计划期间提前折叠到常量,从而导致一个陈旧值在该计划的后续使用中被重新使用。在使用已准备好的语句或者使用缓存计划的函数语言(例如 PL/pgSQL)时,这是有风险的。

对于用 SQL 或任何标准过程语言编写的函数,由易失性类别确定的第二个重要属性,即由调用该函数的 SQL 命令所做的所有数据更改可见性。VOLATILE 函数将看到此类更改,而 STABLEIMMUTABLE 函数则不会看到。此行为使用 MVCC 的快照行为实现(参见 Chapter 13):STABLEIMMUTABLE 函数使用在调用查询开始时建立的快照,而 VOLATILE 函数会在它们执行的每个查询开始时获取一个新的快照。

Note

用 C 编写的函数可以按其需要管理快照,但通常最好让 C 函数也以这种方式工作。

由于此快照行为,只包含 SELECT 命令的函数可以安全地标记为 STABLE,即使它从可能正在被并发查询修改的表中进行选择。PostgreSQL 将使用为调用查询建立的快照执行 STABLE 函数的所有命令,因此它将在整个查询过程中看到数据库的固定视图。

相同的快照行为用于 IMMUTABLE 函数中的 SELECT 命令。通常不建议在 IMMUTABLE 函数中从数据库表中进行选择,因为如果表内容曾经改变,那么不可变性将被破坏。但是,PostgreSQL 并不会强制您不这样做。

一个常见的错误是在其结果依赖于配置参数时给函数标记为 IMMUTABLE。例如,操作时间戳的函数很可能具有依赖于 TimeZone 设置的结果。为了安全起见,应该用 STABLE 标记此类函数。

Note

PostgreSQL 要求 STABLEIMMUTABLE 函数不包含 SELECT 以外的 SQL 命令,以防止修改数据。(这不是一个完全防弹的测试,因为此类函数仍然可以调用修改数据库的 VOLATILE 函数。如果你这样做,你会发现 STABLEIMMUTABLE 函数没有注意到被调用的函数应用的数据库更改,因为它们对自己的快照是隐藏的。)