38.11. 函数优化信息

默认情况下,函数只是一个black box,数据库系统对它的行为了解得很少。 不过,这意味着使用函数的查询执行效率可能会低于它们的能力。可以提供额外的知识帮助计划器优化函数调用。

一些基本事实可以通过CREATE FUNCTION命令中提供的声明性注释来提供。 这里面最重要的是函数的volatility category (IMMUTABLESTABLEVOLATILE);在定义函数时,要始终小心地正确指定这个。 并行安全属性(PARALLEL UNSAFEPARALLEL RESTRICTEDPARALLEL SAFE)也必须被指定,如果你希望在并行查询中使用该函数。 指定函数的估算执行开销也会有作用,和/或集返回函数估计返回的行数。不过,指定这两个事实的声明方式只允许指定常数值,而这通常是不够的。

也可以将一个planner support function 附加到SQL-可调用函数(称为target function), 从而提供关于目标函数的知识,该函数过于复杂而无法以声明方式表示。 计划器支持函数必须写在 C 中(尽管它们的目标函数可以不是),所以这是一个高级功能,相对很少有人会使用。

计划器支持函数必须具有SQL签名

supportfn(internal) returns internal

当建立目标函数时,它通过指定SUPPORT子句附加到它的目标函数。

计划器支持函数的 API 的详细信息可以在 PostgreSQL源代码中的src/include/nodes/supportnodes.h文件中找到。 这里我们提供了计划器支持函数的概述。支持函数的可能请求集合是可扩展的,所以在将来的版本中可能会有更多(功能)。

在规划期间,根据指定函数的特性,一些函数调用可以进行简化。 例如,int4mul(n, 1)可以被简化为n。 这种类型的转换可以通过计划器支持函数执行,通过它实现SupportRequestSimplify请求类型。 对于在查询解析树中找到其目标函数的每个实例,将调用支持函数。如果它发现特定的调用可以简化成某种其他窗体,它可以构建并返回表示该表达式的解析树。 这将为基于函数的操作符自动工作,非常—在刚才的示例中,n * 1也将简化为n。 (但注意这只是一个例子;这个特殊的优化实际上不是标准的PostgreSQL执行)。 我们不保证PostgreSQL在支持函数能够简化的情况下,永远不会调用目标函数。 确保简化表达式与目标函数的实际执行之间严格等效。

对于返回 boolean 的目标函数,估计使用该函数的 WHERE 子句将选择的行的比重通常会有用。 这可以通过实现SupportRequestSelectivity请求类型的支持函数来完成。

如果目标函数的运行时间高度依赖于其输入,提供非固定开销估算可能很有用。这可以通过实现SupportRequestCost请求类型的支持函数来完成。

对于返回集的目标函数,为提供要返回的行数的非常量估计通常很有用。这可以通过实现SupportRequestRows请求类型的支持函数来完成。

对于返回 boolean的目标函数,可以将WHERE中出现的函数调用转换为一个可索引操作符子句或多个子句。 转换的子句可能与函数的条件完全相同,或者它们可能比较弱态一些(也就是说,它们可能接受函数条件所不接受的一些值)。 在后一种情况下,索引条件被称作lossy;它仍然可用于扫描索引,但必须为索引返回的每一行执行函数调用,以看它是否真的通过 WHERE条件或没有。 要建立这样的条件,支持函数必须实现SupportRequestIndexCondition需求类型。