Skip to content

38.11. 函数优化信息#

默认情况下,函数只是一个数据库系统对其行为知之甚少的“黑匣子”。但是,这意味着使用该函数的查询执行效率可能远低于预期。可以提供一些附加知识来帮助计划程序优化函数调用。

CREATE FUNCTION命令中提供的声明性注释可以提供一些基本事实。其中最重要的是函数的波动性类别IMMUTABLESTABLEVOLATILE);定义函数时应始终小心正确指定此类别。如果您希望在并行查询中使用该函数,还必须指定并行安全性属性(PARALLEL UNSAFEPARALLEL RESTRICTEDPARALLEL SAFE)。指定函数的估计执行成本和/或集合返回函数估计返回的行数也可能很有用。但是,指定这两个事实的声明性方式只允许指定一个常量值,这通常是不够的。

还可以将规划器支持函数附加到 SQL 可调用函数(称为其目标函数),从而提供关于目标函数的知识,而这些知识过于复杂,无法通过声明方式表示。规划器支持函数必须用 C 编写(尽管其目标函数可能不是),因此这是一项高级功能,相对较少的人会使用。

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

supportfn(internal) returns internal

在创建目标函数时通过指定SUPPORT子句将其附加到其目标函数。

PostgreSQL源代码中的文件src/include/nodes/supportnodes.h中可以找到规划器支持函数的 API 的详细信息。这里我们仅概述了规划器支持函数可以做什么。对支持函数的可能请求集是可扩展的,因此在未来版本中可能会实现更多功能。

根据函数的特定属性,可以在规划期间简化某些函数调用。例如,int4mul(n, 1)可以简化为n。这种类型的转换可以通过规划器支持函数执行,方法是让它实现SupportRequestSimplify请求类型。将针对在查询解析树中找到的每个目标函数实例调用支持函数。如果它发现可以将特定调用简化为其他形式,则可以构建并返回表示该表达式的解析树。这也会自动适用于基于该函数的操作符——在刚刚给出的示例中,n * 1也将简化为n。(但请注意,这只是一个示例;此特定优化实际上并未由标准PostgreSQL执行。)我们不保证PostgreSQL永远不会在支持函数可以简化的案例中调用目标函数。确保简化表达式与目标函数的实际执行之间具有严格的等效性。

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

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

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

对于返回boolean的目标函数,可以将出现在WHERE中的函数调用转换为可索引运算符子句或子句。转换后的子句可能与函数条件完全等效,或者它们可能稍弱一些(即,它们可能接受函数条件不接受的一些值)。在后一种情况下,索引条件被称为有损;它仍然可用于扫描索引,但必须为索引返回的每一行执行函数调用,以查看它是否真正通过WHERE条件。要创建此类条件,支持函数必须实现SupportRequestIndexCondition请求类型。