选择 打开 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0
历史版本PostgreSQL 9.1 已于 2016 年 10 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

35.6. 函数易变性分类 #

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

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

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

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

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

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

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

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

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

注意

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

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

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

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

注意

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

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。