2025年9月25日: PostgreSQL 18 发布!
支持的版本: 当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本: devel
不再支持的版本: 12

36.11. 函数优化信息 #

默认情况下,一个函数只是一个数据库系统对其行为知之甚少的“黑盒子”。然而,这意味着使用该函数的查询的执行效率可能远不如它们应有的效率。可以通过提供额外的知识来帮助优化器优化函数调用。

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

还可以将一个 优化器支持函数 附加到一个 SQL 可调用的函数(称为其 目标函数),从而提供有关目标函数的一些过于复杂而无法声明式表示的知识。优化器支持函数必须用 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 子句中的函数调用转换为一个或多个可索引的运算符子句。转换后的子句可能与函数的条件完全等价,也可能稍弱一些(即,它们可能接受函数条件不接受的某些值)。后一种情况下的索引条件称为 有损;它仍然可以用来扫描索引,但必须为索引返回的每一行执行函数调用,以查看它是否确实通过了 WHERE 条件。要创建这样的条件,支持函数必须实现 SupportRequestIndexCondition 请求类型。

提交更正

如果您在文档中发现任何不正确的内容,与您对特定功能的实际体验不符,或者需要进一步澄清,请使用 此表单 报告文档问题。