是的,它可能会损害性能。
简单的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
函数,那么您不必先“作弊”。
FORCE
无论哪种方式,我们都应该能够做到。经验丰富的PostgreSQL DBA的100%都希望通过包装函数来解决该UI。至少使用FORCE
,我们不需要包装器,也不必依赖声明的fn波动率。