Postgresql 中文操作指南
38.7. Function Volatility Categories #
每个函数都有一个 volatility 类别,其可能性是 VOLATILE 、 STABLE 或 IMMUTABLE 。如果 CREATE FUNCTION 命令没有指定一个类别,则 VOLATILE 是默认值。波动性类别是对优化器关于函数行为的承诺:
为了获得最佳优化结果,您应使用对其有效的最严格的可变性类别为函数进行标记。
任何具有副作用的函数 must 都必须标记为 VOLATILE,以便无法优化掉调用它的情况。即使某个函数没有副作用,如果其值在单个查询内可能会发生更改,也需要将其标记为 VOLATILE;其中一些示例包括 random()、currval()、timeofday()。
另一个重要示例是 current_timestamp 函数族限定为 STABLE,因为它们的不在一个事务内更改。
考虑计划并且立即执行的简单交互式查询时,STABLE 和 IMMUTABLE 类别之间的差异相对较小:函数是在计划期间执行一次还是在查询执行启动期间执行一次,这无关紧要。但是,如果计划被保存并且以后被重新使用,则差异就很大。当函数实际上不是 IMMUTABLE 时将其标记为 IMMUTABLE,可能允许它在计划期间提前折叠到常量,从而导致一个陈旧值在该计划的后续使用中被重新使用。在使用已准备好的语句或者使用缓存计划的函数语言(例如 PL/pgSQL)时,这是有风险的。
对于用 SQL 或任何标准过程语言编写的函数,由易失性类别确定的第二个重要属性,即由调用该函数的 SQL 命令所做的所有数据更改可见性。VOLATILE 函数将看到此类更改,而 STABLE 或 IMMUTABLE 函数则不会看到。此行为使用 MVCC 的快照行为实现(参见 Chapter 13):STABLE 和 IMMUTABLE 函数使用在调用查询开始时建立的快照,而 VOLATILE 函数会在它们执行的每个查询开始时获取一个新的快照。
Note
用 C 编写的函数可以按其需要管理快照,但通常最好让 C 函数也以这种方式工作。
由于此快照行为,只包含 SELECT 命令的函数可以安全地标记为 STABLE,即使它从可能正在被并发查询修改的表中进行选择。PostgreSQL 将使用为调用查询建立的快照执行 STABLE 函数的所有命令,因此它将在整个查询过程中看到数据库的固定视图。
相同的快照行为用于 IMMUTABLE 函数中的 SELECT 命令。通常不建议在 IMMUTABLE 函数中从数据库表中进行选择,因为如果表内容曾经改变,那么不可变性将被破坏。但是,PostgreSQL 并不会强制您不这样做。
一个常见的错误是在其结果依赖于配置参数时给函数标记为 IMMUTABLE。例如,操作时间戳的函数很可能具有依赖于 TimeZone 设置的结果。为了安全起见,应该用 STABLE 标记此类函数。