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

36.7. 函数易变性分类 #

每一个函数都有一个易变性分类,可能是VOLATILESTABLE或者IMMUTABLE。 如果 CREATE FUNCTION命令没有指定一个分类,则默认是VOLATILE。 易变性分类是给优化器的关于该函数行为的一种承诺:

为了最好的优化结果,你应该把函数标记为对它们合法的易变性分类中最严格 的那种。

任何带有副作用的函数必须被标记为VOLATILE, 这样对它的调用就不能被优化掉。甚至如果一个函数的值在一个查询中会 变化,即使它没有副作用也需要被标记为VOLATILE。这样的 示例有random()currval()timeofday()等。

另一种重要的示例是current_timestamp家族的函数有资格 被标记为STABLE,因为它们的值在一个事务中不会改变。

在考虑先规划然后立即执行的简单交互式查询时,在STABLEIMMUTABLE分类间的区别相对较小:一个函数是在规划时只 执行一次还是在查询执行开始期间只执行一次没有太大关系。但是如果计划 被保存下来然后在后面被重用,区别就大了。如果在不允许过早把一个函数 变成规划期间的一个常数时把它标记为IMMUTABLE,会导致 在后续重用该计划时继续使用陈旧的值。在使用预备语句,或使用会缓存执行计划的函数语言(如 PL/pgSQL)时,这会带来严重问题。

对于用 SQL 或者其他任何标准过程语言编写的函数,还有第二种由易变性分类 决定的特性,即由调用该函数的 SQL 命令所作的数据修改的可见性。 VOLATILE函数将看到这些更改,STABLE 或者IMMUTABLE函数则看不到。这种行为使用 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函数不会发现由被调 用函数所作的数据库改变,因为它们对它的快照不可见)。