受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

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 中的函数调用转换成一个或多个可索引的操作符子句。转换后的子句可能与函数条件完全等价,也可能稍弱一些,也就是说,它们可能会接受一些原本不满足函数条件的值。在后一种情况下,这个索引条件就称为有损的(lossy);它仍然可以用于扫描索引,但对索引返回的每一行,仍必须再执行一次函数调用,以确认该行是否真的满足 WHERE 条件。要构造这种条件,支持函数必须实现 SupportRequestIndexCondition 请求类型。

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。