# 38.7.函数波动类别

每个函数都有一个波动分类,可能性是不稳定的,稳定的不变的.不稳定的如果创建函数命令未指定类别。波动性类别向优化器承诺函数的行为:

  • A.不稳定的函数可以做任何事情,包括修改数据库。对于具有相同参数的连续调用,它可以返回不同的结果。优化器对这些函数的行为不做任何假设。使用volatile函数的查询将在需要函数值的每一行重新计算该函数。

  • A.稳定的函数无法修改数据库,并且如果在一条语句中的所有行都有相同的参数,则保证返回相同的结果。此类别允许优化器将函数的多个调用优化为单个调用。特别是,在索引扫描条件下使用包含此类函数的表达式是安全的。(由于索引扫描只会计算一次比较值,而不是每行一次,因此使用不稳定的在索引扫描条件下运行。)

  • 不变的函数不能修改数据库,并保证在给定相同参数的情况下永远返回相同的结果。此类别允许优化器在查询使用常量参数调用函数时对其进行预评估。例如,像选择其中x=2+2一眼就可以简化为选择其中x=4,因为整数加法运算符下面的函数被标记为不变的.

    为了获得最佳的优化结果,你应该给你的函数贴上对它们有效的最严格的波动性类别。

    有副作用吗必须被贴上标签不稳定的,因此无法优化对它的调用。即使是没有副作用的功能也需要贴标签不稳定的如果其值可以在单个查询中更改;例如随机的, currval(), 每日时间.

    另一个重要的例子是当前时间戳函数族被称为稳定的,因为它们的值在事务中不会更改。

    两者之间的差别相对较小稳定的不变的在考虑已计划并立即执行的简单交互式查询时,分类:函数在计划期间执行一次或在查询执行启动期间执行一次都无关紧要。但是,如果计划被保存并在以后重新使用,情况会有很大的不同。标记函数不变的当它真的不是时,可能会允许它在规划期间过早地折叠为常量,导致在后续使用计划时重复使用过时的值。当使用准备好的语句或使用缓存计划的函数语言(如PL/pgSQL)时,这是一种危险。

    对于用SQL或任何标准过程语言编写的函数,还有第二个重要属性由volatility类别确定,即调用函数的SQL命令所做的任何数据更改的可见性。A.不稳定的函数将看到这样的变化稳定的不变的功能不会改变。此行为是使用MVCC的快照行为实现的(请参见第13章): 稳定的不变的函数使用在调用查询开始时建立的快照,而不稳定的函数在执行每个查询时都会获得一个新的快照。

# 笔记

用C编写的函数可以随心所欲地管理快照,但让C函数以这种方式工作通常也是个好主意。

由于这种快照行为,函数只包含选择可以安全地标记命令稳定的,即使它从可能正在通过并发查询进行修改的表中进行选择。PostgreSQL将执行稳定的函数使用为调用查询建立的快照,因此它将在整个查询中看到数据库的固定视图。

同样的快照行为也用于选择内部命令不变的功能。在数据库中从数据库表中进行选择通常是不明智的不变的函数,因为如果表内容发生变化,不变性将被破坏。然而,PostgreSQL并没有强制要求您不要这样做。

一个常见的错误是标记函数不变的当其结果取决于配置参数时。例如,一个操作时间戳的函数很可能会产生依赖于时区背景为安全起见,此类功能应贴上标签稳定的相反

# 笔记

PostgreSQL要求稳定的不变的函数只包含SQL命令选择防止数据修改。(这不是一个完全防弹的测试,因为这样的函数仍然可以调用不稳定的修改数据库的函数。如果你这样做,你会发现稳定的不变的函数不会注意到被调用函数应用的数据库更改,因为它们在其快照中是隐藏的。)