↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0
历史版本。 PostgreSQL 8.4 已结束支持。 请参阅 当前版本手册.

34.6. 函数易变性分类 #

每一个函数都有一个易变性分类,可能的类别是 VOLATILE,STABLE 或 IMMUTABLE。VOLATILE 会作为默认类别,条件是CREATE FUNCTION命令没有指定类别。易变性分类是给优化器的关于该函数行为的一种承诺:

  • 一个VOLATILE函数可以做任何事情,包括修改数据库。在使用相同的参数连续调用时,它能返回不同的结果。优化器不会对这类函数的行为做任何假定。使用易变函数的查询会在需要该函数值的每一行上重新对它求值。

  • 一个STABLE函数不能修改数据库并且被确保对一个语句中的所有行用给定的相同参数返回相同的结果。这种分类允许优化器把该函数的多个调用优化成一个调用。特别是,在一个索引扫描条件中使用包含这样一个函数的表达式是安全的(因为一次索引扫描只会计算一次比较值,而不是为每一行都计算一次,在一个索引扫描条件中不能使用 VOLATILE函数)。

  • 一个IMMUTABLE函数不能修改数据库并且被确保用相同的参数永远返回相同的结果。这种分类允许优化器在一个查询用常量参数调用该函数时提前计算该函数。例如,一个 SELECT ... WHERE x = 2 + 2这样的查询可以被简化为 SELECT ... WHERE x = 4,因为整数加法操作符底层的函数被标记为IMMUTABLE。

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

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

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

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

对于用 SQL 或者其他任何标准过程语言编写的函数,还有第二种由易变性分类决定的特性,即由调用该函数的 SQL 命令所作的数据修改的可见性。VOLATILE函数将看到这些更改,STABLE 或者IMMUTABLE函数则看不到。这种行为使用 MVCC 的快照行为(见第 13 章)实现:STABLE和 IMMUTABLE函数使用一个在调用查询开始时建立的快照,而 VOLATILE函数在它们执行的每一个查询的开始都获得一个新鲜的快照。

注意

用 C 编写的函数按照它们自己需要的方式管理快照,但是通常最好让 C 函数也按照上面的方式来。

由于这种快照行为,只包含 SELECT 命令的函数可以安全地标记为 STABLE,即使它查询的表可能正被并发查询修改。PostgreSQL 会使用为调用查询建立的快照来执行 STABLE 函数中的所有命令,因而该函数在整个查询期间看到的都是数据库的固定视图。

对 IMMUTABLE 函数中的 SELECT 也采用同样的快照行为。一般来说,在 IMMUTABLE 函数里查询数据库表并不明智,因为一旦表内容发生变化,就会破坏其不变性。不过,PostgreSQL 并不会强制禁止这样做。

一种常见的错误是当一个函数的结果依赖于一个配置参数时把它标记为 IMMUTABLE。例如,一个操纵时间戳的函数有可能结果依赖于timezone设置。为了安全起见,这类函数应该被标记为STABLE。

注意

在 PostgreSQL 8.0 版之前,STABLE 和 IMMUTABLE 函数不能修改数据库这项要求并未被系统强制执行。8.0 及之后的版本会强制执行它,方式是要求这些类别的 SQL 函数和过程语言函数不包含 SELECT 之外的 SQL 命令。(这并不是一个完全万无一失的测试,因为这类函数仍可能调用修改数据库的 VOLATILE 函数。如果你这样做,会发现 STABLE 或 IMMUTABLE 函数不会注意到被调用函数所做的数据库更改,因为这些更改对它的快照是隐藏的。)

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.