默认情况下,函数仅仅是一个“黑盒子”,而数据库系统对其行为所知甚少。然而,这意味着使用该函数的查询可能执行的效率会远低于可能达到的效率。可以通过提供一些附加知识来帮助规划器优化函数调用。
一些基本事实可以通过 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
请求类型。