Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

36.7. 函数波动性类别 #

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

为了获得最佳优化效果,您应该用对它们有效的波动性类别最严格的给您的函数贴上标签。

任何有副作用的函数必须标为 VOLATILE,这样对它们的调用才不会被优化掉。即使没有副作用的函数也需要标为 VOLATILE,如果其值在单个查询内可能更改;一些示例是 random()currval()timeofday()

另一个重要示例是 current_timestamp 函数系列符合 STABLE,这是因为它们的值在事务中不会更改。

对于考虑直接执行的简单交互式查询来说,STABLEIMMUTABLE 类别之间的差异很小:函数在计划期间执行一次还是在查询执行启动期间执行一次并无多大要紧。但如果计划之后保存并重新使用,则差别很大。将一个函数错误地标记为 IMMUTABLE 时,可能导致它在计划期间过早地折叠为常数,进而在随后的计划使用期间再次使用过时的值。在使用预处理语句或使用缓存计划的函数语言(如 PL/pgSQL)时,这是一种危险。

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

注意

用 C 编写的函数可以按它们想要的方式管理快照,但通常最好也让 C 函数采用此方式。

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

相同的快照行为用于 IMMUTABLE 函数中的 SELECT 命令。通常不建议在 IMMUTABLE 函数中从数据库表中进行选择,因为如果表内容发生更改,不可变性将被破坏。不过,PostgreSQL 并没有强制执行这一点。

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

注意

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