声明函数波动是否IMMUTABLE会损害性能?


9

Postgres函数用波动性分类VOLATILESTABLEIMMUTABLE声明。众所周知,该项目使用内置功能的这些标签非常严格。并且有充分的理由。一个突出的例子:表达式索引仅允许IMMUTABLE函数,并且它们必须是真正不变的,以避免错误的结果。

用户定义的函数仍然可以自由地声明,如所有者选择的那样。该手册建议:

为了获得最佳的优化结果,您应该使用对它们有效的最严格的波动性类别来标记您的函数。

...并添加了错误的波动率标签可能会出错的大量问题列表。

尽管如此,在某些情况下伪造的不变性还是有意义的。通常,当您知道该函数在您的范围内实际上是不变的。例:

除了对数据完整性的所有可能影响,对性能有什么影响?人们可能会认为声明一个函数IMMUTABLE只会对性能有所帮助。是这样吗?

声明功能波动会IMMUTABLE 损害性能吗?

让我们假设当前的Postgres 10缩小了范围,但是所有最新版本都很有趣。


1
同样要注意的是,表达索引上的整个“真正不可变的”都是真实的皮塔饼。这是一个可怕的用户界面。FORCE无论哪种方式,我们都应该能够做到。经验丰富的PostgreSQL DBA的100%都希望通过包装函数来解决该UI。至少使用FORCE,我们不需要包装器,也不必依赖声明的fn波动率。
埃文·卡罗尔

1
我假设FORCE应该使表达式索引接受非不变的函数(同时将它们标记为潜在的故障点)。是的,这似乎比不可变的函数包装器更为优雅。
Erwin Brandstetter

我对PostGres几乎一无所知,但波动率不是多余的吗?这是什么意思?真的不期望这是可靠的,因为这很疯狂吗?
安东尼

@安东尼:我澄清了一些。单击链接以获取详细信息。
Erwin Brandstetter

Answers:


7

是的,它可能会损害性能。

简单的SQL函数可以在调用查询中“内联”引用Postgres Wiki

LANGUAGE SQL在某些条件下,SQL函数(即)会将其函数体内联到调用查询中,而不是直接调用它们。这可能具有实质性的性能优势, 因为函数主体会暴露给调用查询的计划者,这可以应用优化方法,例如恒定折叠,限定下推等。

大胆强调我的。

为了确保正确性,有许多先决条件。其中之一

如果声明了函数IMMUTABLE,则表达式不得调用任何非不变的函数或运算符

这意味着,使用任何非不变函数但仍被声明的SQL函数IMMTUTABLE将从此优化中排除。由SO上的这些相关答案触发,我一直在进行广泛的测试:

基本上比较简单SQL函数的这两个变体(将日期映射到integer,忽略与目的无关的年份):

CREATE FUNCTION f_mmdd_tc_s(date) RETURNS int LANGUAGE sql STABLE    AS
$$SELECT to_char($1, 'MMDD')::int$$;

CREATE FUNCTION f_mmdd_tc_i(date) RETURNS int LANGUAGE sql IMMUTABLE AS
$$SELECT to_char($1, 'MMDD')::int$$;  -- cannot be inlined!

Postgres函数to_char()仅为STABLE,而不是IMMUTABLE(它的所有重载实例- 出于超出此答案范围的原因)。因此,第二个是伪造的IMMUTABLE在一个简单的测试中结果却5倍

db <> 在这里拨弄

可以用以下等效示例替换此特定示例

CREATE FUNCTION f_mmdd(date) RETURNS int LANGUAGE sql IMMUTABLE AS
$$SELECT (EXTRACT(month FROM $1) * 100 + EXTRACT(day FROM $1))::int$$;

好像有两个函数调用和更多的计算更加昂贵。但是IMMUTABLE标签是正确的(此外,使用的功能更快,强制text使用integer也更昂贵)。

速度是上述最快变体的2倍(慢变体的10倍)。重点是:在可能的地方使用IMMUTABLE函数,那么您不必先“作弊”。


很酷的发现!立即进行追踪:dba.stackexchange.com/q/212198/2639
Evan Carroll

您知道我想念的我不知道的地方。那STABLE也是内联的。我以为优化器只会在线IMMUTABLE运行。
埃文·卡罗尔

VOLATILE一样。
Erwin Brandstetter

Wiki说该函数被声明为STABLE或IMMUTABLE wiki.postgresql.org/wiki/Inlining_of_SQL_functions
Evan Carroll

..在“ 表函数的内联条件”下。不适用于标量函数。我证明它在小提琴:dbfiddle.uk/...
欧文Brandstetter修改
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.