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

38.7. 函数波动性类别 #

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

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

任何具有副作用的函数必须标记为VOLATILE,这样才能避免对其进行优化。即使没有副作用的函数,如果其值在单个查询中发生更改,也需要将其标记为VOLATILE;一些示例包括random()currval()timeofday()

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

在考虑计划并立即执行的简单交互式查询时,STABLEIMMUTABLE类别之间的差异相对较小:函数在计划期间执行一次还是在查询执行启动期间执行一次并不重要。但是,如果计划被保存并稍后重新使用,则会有很大差异。在函数实际上不是IMMUTABLE时将其标记为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 函数不会注意到被调用函数应用的数据库更改,因为它们被隐藏在其快照中。)