默认情况下,一个函数只是一个数据库系统对其行为知之甚少的“黑盒子”。然而,这意味着使用该函数的查询的执行效率可能远不如它们应有的效率。可以通过提供额外的知识来帮助优化器优化函数调用。
一些基本事实可以通过 CREATE FUNCTION
命令中提供的声明性注解来提供。其中最重要的是函数的 易变性类别(IMMUTABLE
、STABLE
或 VOLATILE
);在定义函数时,应始终谨慎正确地指定此项。如果希望在并行化查询中使用该函数,还必须指定并行安全属性(PARALLEL UNSAFE
、PARALLEL RESTRICTED
或 PARALLEL 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
请求类型。
如果您在文档中发现任何不正确的内容,与您对特定功能的实际体验不符,或者需要进一步澄清,请使用 此表单 报告文档问题。