Postgresql 中文操作指南

38.11. Function Optimization Information #

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

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

也可以将 planner support function 附加到 SQL 可调用函数(称为其 target function),并由此提供关于目标函数的知识,而这些知识太复杂,无法通过声明性方式表示。规划程序支持函数必须用 C 编写(尽管其目标函数不必用 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 中的函数调用转换成一个或多个可索引操作符子句。转换后的子句可能与函数的条件完全等价,或者在一定程度上较弱(即,它们可能接受函数条件所不接受的一些值)。在后一种情况下,索引条件被称为 lossy;它仍然可用于扫描索引,但必须针对索引返回的每一行执行函数调用,以查看它是否真的通过了 WHERE 条件。为了创建这样的条件,支持函数必须实现 SupportRequestIndexCondition 请求类型。