默认情况下,函数只是一个“黑盒”,数据库系统对其行为知之甚少。然而,这意味着使用该函数的查询执行效率可能远低于它们本可以达到的效率。可以提供额外的知识来帮助规划器优化函数调用。
可以通过在 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
请求类型。
如果您发现文档中任何不正确的内容,或者与您在使用特定功能时的体验不符,或者需要进一步澄清,请使用此表单报告文档问题。