【发布时间】:2013-08-15 18:11:29
【问题描述】:
为了获得最佳优化结果,您应该使用对其有效的最严格的波动率类别来标记您的函数。
但是,我似乎有一个例子,情况并非如此,我想了解发生了什么。 (背景:我正在运行 postgres 9.2)
我经常需要将表示为整数秒的时间转换为日期。我写了一个函数来做到这一点:
CREATE OR REPLACE FUNCTION
to_datestamp(time_int double precision) RETURNS date AS $$
SELECT date_trunc('day', to_timestamp($1))::date;
$$ LANGUAGE SQL;
让我们将性能与其他相同的函数进行比较,将波动率设置为 IMMUTABLE 和 STABLE:
CREATE OR REPLACE FUNCTION
to_datestamp_immutable(time_int double precision) RETURNS date AS $$
SELECT date_trunc('day', to_timestamp($1))::date;
$$ LANGUAGE SQL IMMUTABLE;
CREATE OR REPLACE FUNCTION
to_datestamp_stable(time_int double precision) RETURNS date AS $$
SELECT date_trunc('day', to_timestamp($1))::date;
$$ LANGUAGE SQL STABLE;
为了测试这一点,我将创建一个包含 10^6 个随机整数的表,对应于 2010-01-01 和 2015-01-01 之间的时间
CREATE TEMPORARY TABLE random_times AS
SELECT 1262304000 + round(random() * 157766400) AS time_int
FROM generate_series(1, 1000000) x;
最后,我会在这个表上调用这两个函数;在我的特定盒子上,原始版本大约需要 6 秒,不可变版本大约需要 33 秒,稳定版本大约需要 6 秒。
EXPLAIN ANALYZE SELECT to_datestamp(time_int) FROM random_times;
Seq Scan on random_times (cost=0.00..20996.62 rows=946950 width=8)
(actual time=0.150..5493.722 rows=1000000 loops=1)
Total runtime: 6258.827 ms
EXPLAIN ANALYZE SELECT to_datestamp_immutable(time_int) FROM random_times;
Seq Scan on random_times (cost=0.00..250632.00 rows=946950 width=8)
(actual time=0.211..32209.964 rows=1000000 loops=1)
Total runtime: 33060.918 ms
EXPLAIN ANALYZE SELECT to_datestamp_stable(time_int) FROM random_times;
Seq Scan on random_times (cost=0.00..20996.62 rows=946950 width=8)
(actual time=0.086..5295.608 rows=1000000 loops=1)
Total runtime: 6063.498 ms
这里发生了什么?例如,由于传递给函数的参数不太可能重复,postgres 是否花时间缓存结果实际上并没有帮助?
(我正在运行 postgres 9.2。)
谢谢!
更新
感谢Craig Ringer,这已在pgsql-performance mailing list 上进行了讨论。亮点:
[ 耸耸肩... ] 使用 IMMUTABLE 对函数的可变性撒谎 (在这种情况下,date_trunc)是个坏主意。很可能导致错误 答案,别管性能问题。在这种特殊情况下,我 想象一下性能问题来自于抑制选项 内联函数体......但你应该更担心 在其他情况下,您是否没有得到完全虚假的答案。
如果我理解,使用 IMMUTABLE 标志会禁用内联。你看到的,是 SQL 评估溢出。我的规则是——尽可能不要在 SQL 函数中使用标志。
【问题讨论】:
-
我的印象是 immutable 不能用于与随机或时区相关的任何东西,所以我猜它在运行时在内部将您的函数转换为 VOLATILE。
-
嗯,文档警告“一个常见的错误是当函数的结果依赖于配置参数时将其标记为 IMMUTABLE。例如,操作时间戳的函数很可能具有依赖于 TimeZone 设置的结果. 为了安全起见,此类功能应改为 STABLE。但我不确定这会如何影响性能。
-
请显示
explain analyze生成的实际计划。您可以将它们粘贴到 explain.depesz.com 并在需要时将链接放在这里。STRICT通常会影响性能(它会阻止 SQL 函数的内联),但 添加IMMUTABLE不应该 AFAIK。 -
@CraigRinger 快速搜索档案让我相信 a)。我对神奇地发生不可变到易失性的事情是错误的,并且b)。我在考虑最近关于 STABLE 和 IMMUTABLE(不一定是 VOLATILE)的线程。这是一个链接,Tom Lane 直接与我之前的假设相矛盾:markmail.org/message/sekx7mjhq27vxu7d
-
@bma:我认为它是一个功能,你可以强制一个函数为
IMMUTABLE。 Here is one application。当然,你需要知道他在搞什么鬼。
标签: performance postgresql user-defined-functions