PostgreSQL 函数优化信息
默认情况下,函数只是一个“black box”,数据库系统对它的行为了解得很少。 不过,这意味着使用函数的查询执行效率可能会低于它们的能力。可以提供额外的知识帮助计划器优化函数调用。
一些基本事实可以通过CREATE FUNCTION命令中提供的声明性注释来提供。 这里面最重要的是函数的volatility category (
IMMUTABLE
、 STABLE
或 VOLATILE
);在定义函数时,要始终小心地正确指定这个。 并行安全属性(PARALLEL UNSAFE
、PARALLEL RESTRICTED
或PARALLEL SAFE
)也必须被指定,如果你希望在并行查询中使用该函数。
指定函数的估算执行开销也会有作用,和/或集返回函数估计返回的行数。不过,指定这两个事实的声明方式只允许指定常数值,而这通常是不够的。
也可以将一个planner support function 附加到SQL-可调用函数(称为target function), 从而提供关于目标函数的知识,该函数过于复杂而无法以声明方式表示。 计划器支持函数必须写在 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
需求类型。