【发布时间】:2012-01-17 07:36:51
【问题描述】:
当一个简单的 SQL 函数声明为 STRICT 而 answering this question 时,我偶然发现了性能下降。
为了演示,我创建了一个函数的两个变体,按升序对数组的两个元素进行排序。
测试设置
包含 10000 个随机整数对的表(
CREATE TABLE tbl (arr int[]);
INSERT INTO tbl
SELECT ARRAY[(random() * 1000)::int, (random() * 1000)::int]
FROM generate_series(1,10000);
没有STRICT修饰符的函数:
CREATE OR REPLACE FUNCTION f_sort_array(int[])
RETURNS int[]
LANGUAGE sql IMMUTABLE AS
$func$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$func$;
带有STRICT 修饰符的函数(否则相同):
CREATE OR REPLACE FUNCTION f_sort_array_strict(int[])
RETURNS int[]
LANGUAGE sql IMMUTABLE STRICT AS
$func$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$func$;
结果
我执行了大约 20 次,并从 EXPLAIN ANALYZE 中获得了最好的结果。
SELECT f_sort_array(arr) FROM tbl; -- Total runtime: 43 ms
SELECT f_sort_array_strict(arr) FROM tbl; -- Total runtime: 103 ms
这些是 Debian Squeeze 上 Postgres 9.0.5 的结果。 8.4 上的类似结果。
在所有 NULL 值的测试中,两个函数执行相同:~37 ms。
我做了一些研究,发现了一个有趣的问题。在大多数情况下,声明 SQL 函数 STRICT 会禁用函数内联。在PostgreSQL Online Journal 或pgsql-performance mailing list 或Postgres Wiki 中了解更多信息。
但我不太确定这是怎么解释的。在这个简单的场景中,不内联函数会导致性能下降?没有索引,没有光盘读取,没有排序。可能是通过内联函数简化了重复函数调用的开销?
重新测试
相同的测试,相同的硬件,Postgres 9.1。更大的差异:
SELECT f_sort_array(arr) FROM tbl; -- Total runtime: 27 ms
SELECT f_sort_array_strict(arr) FROM tbl; -- Total runtime: 107 ms
相同的测试,新硬件,Postgres 9.6。差距更大,然而:
SELECT f_sort_array(arr) FROM tbl; -- Total runtime: 10 ms
SELECT f_sort_array_strict(arr) FROM tbl; -- Total runtime: 60 ms
【问题讨论】:
-
这两个函数不是等价的。
STRICT不是提示而是指令,“不要使用空参数调用它”。这将导致您没有明确要求的非空检查,因此评论不回答。然而,令我惊讶的是,当我在带有NOT NULL修饰符的表上测试它时,它仍然具有相同的效果。 -
@couling:无论有没有 STRICT,示例函数都会产生相同的结果。如果涉及 NULL 值,“常识”会告诉我 STRICT 更快,但事实并非如此。我在我的问题中添加了一个带有 NULL 的快速测试。
-
不涉及空值并不意味着 postgres 知道它们不涉及。可能还需要检查。
-
很好且经过充分研究的问题,为什么投反对票!?
-
Pg 开发者必须阅读这篇文章作为错误报告。 BigBig 性能损失破坏了对
STRICT用户的任何期望。
标签: postgresql performance sql-function strict postgresql-performance