postgres 函数:IMMUTABLE 何时会损害性能?

2024-03-11

The Postgres 文档 http://www.postgresql.org/docs/9.2/static/xfunc-volatility.html say

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

然而,我似乎有一个例子,情况并非如此,我想了解发生了什么。 (背景:我正在运行 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。)

Thanks!

UPDATE

谢谢克雷格·林格 https://stackoverflow.com/users/398670/craig-ringer这已经在pgsql-性能邮件列表 http://www.postgresql.org/message-id/520AD240.9060508@2ndquadrant.com。强调:

汤姆·莱恩 说 http://www.postgresql.org/message-id/22812.1376453860@sss.pgh.pa.us

[耸耸肩...]使用 IMMUTABLE 来掩盖函数的可变性 (在本例中为 date_trunc)是一个坏主意。很可能会导致错误 答案,不用担心性能问题。在这个特殊的例子中,我 想象性能问题来自于抑制该选项 内联函数体......但你应该更担心 在其他情况下您是否没有得到完全虚假的答案。

帕维尔·斯特胡勒 说 http://www.postgresql.org/message-id/CAFj8pRBF3Qr7WtQwO1H_WN=hhFGk0semwhdE+ODz3iyv-TroMQ@mail.gmail.com

如果我理解的话,使用的 IMMUTABLE 标志会禁用内联。你所看到的,是 SQL 评估溢出。我的规则是 - 如果可能的话,不要在 SQL 函数中使用标志。


问题是to_timestamp返回带有时区的时间戳。如果to_timestamp函数被替换为无时区的“手动”计算,性能没有差异

create or replace function to_datestamp_stable(
    time_int double precision
) returns date as $$
  select date_trunc('day', timestamp 'epoch' + $1 * interval '1 second')::date;
$$ language sql stable;

explain analyze
select to_datestamp_stable(a)
from generate_series(1, 1000000) s (a);
                                                         QUERY PLAN                                                          
-----------------------------------------------------------------------------------------------------------------------------
 Function Scan on generate_series s  (cost=0.00..22.50 rows=1000 width=4) (actual time=96.962..433.562 rows=1000000 loops=1)
 Total runtime: 459.531 ms

create or replace function to_datestamp_immutable(
    time_int double precision
) returns date as $$
  select date_trunc('day', timestamp 'epoch' + $1 * interval '1 second')::date;
$$ language sql immutable;

explain analyze
select to_datestamp_immutable(a)
from generate_series(1, 1000000) s (a);
                                                         QUERY PLAN                                                          
-----------------------------------------------------------------------------------------------------------------------------
 Function Scan on generate_series s  (cost=0.00..22.50 rows=1000 width=4) (actual time=94.188..433.492 rows=1000000 loops=1)
 Total runtime: 459.434 ms

相同的功能使用to_timestamp

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;

explain analyze
select to_datestamp_stable(a)
from generate_series(1, 1000000) s (a);
                                                          QUERY PLAN                                                          
------------------------------------------------------------------------------------------------------------------------------
 Function Scan on generate_series s  (cost=0.00..20.00 rows=1000 width=4) (actual time=91.924..3059.570 rows=1000000 loops=1)
 Total runtime: 3103.655 ms

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;

explain analyze
select to_datestamp_immutable(a)
from generate_series(1, 1000000) s (a);
                                                           QUERY PLAN                                                           
--------------------------------------------------------------------------------------------------------------------------------
 Function Scan on generate_series s  (cost=0.00..262.50 rows=1000 width=4) (actual time=92.639..20083.920 rows=1000000 loops=1)
 Total runtime: 20149.311 ms
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

postgres 函数:IMMUTABLE 何时会损害性能? 的相关文章

随机推荐

  • 更改声音文件的速度

    我正在寻找改变声音文件的速度 但不知道如何实现它 我假设在减慢速度的情况下必须进行某种类型的插值 但不确定如何实现加速 也许是几个样本的平均值 无论是改变节奏还是音调 目前并不重要 我想学习如何实现这两者 但至少想先完成其中一个 如果有人对
  • 如何更改32位寄存器的特定位而不更改其他位?

    我想直接使用寄存器的物理地址来操作寄存器的某些位 但是我找不到方法来做到这一点 我看到一些关于设置位掩码的帖子 但我发现它们太令人困惑了 我的寄存器物理地址是 0x4A10005C 我想操纵它的 18 16 位之间的位 我想设置0x3在那些
  • 这个模板语法“typename = T”是什么意思?

    有时我会看到这样的语法 template
  • 如何使用 PAC(代理自动配置)通过 Fiddler 调试 Htmlunit 流量

    我有一个使用 Htmlunit 的应用程序 需要放置 Fiddler 来拦截流量 我读了一些有关通过附带的 PAC 代理自动配置 javascript 文件配置它的内容 但我无法再次找到该文章 如何通过 PAC 配置 Htmlunit PA
  • 为什么声明字符串时不需要分配内存[重复]

    这个问题在这里已经有答案了 我是 C 新手 目前我正在尝试了解指针是如何工作的 这是一个让我困惑的问题 据我所知 在给指针赋值之前 应该为该指针分配一定的内存 如果我错了 请纠正我 如下面的代码 int main void int i in
  • 从 Haskell 列表中删除重复元素

    我是 Haskell 的初学者 我只是想知道如何实现一个函数来从数组中删除重复元素 例如 1 1 1 3 4 2 2 3 结果应为 1 3 4 2 我不想使用一些现有的函数 例如 element 并通过使用递归来实现它 我的想法是比较 x
  • 调暗屏幕的正确方法是什么?

    到目前为止 我在搜索中看到了两种方法 这两种方法我都遇到了麻烦 方法一 Settings System putInt getContentResolver Settings System SCREEN BRIGHTNESS 100 方法2
  • 我应该使用 ASP.NET 会话还是避免使用它们,为什么?

    我应该使用 ASP NET 会话还是避免使用它们 为什么 对于新的应用程序 我试着避开他们 https stackoverflow com questions 526697 upgrade from net 3 0 to 3 5 sites
  • DirectX 与 VB.NET

    是否有一组有关 DirectX 9 或更高版本 的文档 其中显示了将 DirectX 9 或更高版本 与 VB NET 一起使用的对象 方法 属性 事件和示例代码 最新的 SDK 包含 C 的详细信息 而 Windows DiectX 图形
  • 无需任何代码即可在 xml 文件中定义 Tabhost/TabWidget + 内容 - 这可能吗?

    是否可以仅在布局 xml 文件中定义选项卡布局 每次我找到 tabhost 教程时 它都只能与一些额外的 java 代码一起使用 这是我的 test xml 它不显示任何选项卡
  • 创建一个可变的 java.lang.String

    众所周知 JavaStrings 是不可变的 自 java 诞生以来 不可变字符串就是它的一个重要补充 不变性允许快速访问和大量优化 与 C 样式字符串相比 显着减少出错的可能性 并有助于实施安全模型 可以在不使用 hack 的情况下创建一
  • sqlalchemy 唯一约束 VS 索引(unique=True)

    我正在使用 MySQL 运行 InnoDB 并使用 sqlalchemy 包装整个内容 现在 我想使用 请参阅docs http sqlalchemy utils readthedocs io en latest database help
  • 将分层 xml 绑定到树视图

    我有一个标准的 NET 3 5 winforms 项目 在它上面 它有一个树视图 我已使用 XmlSerializer 和相关类将 List 实例序列化为 XML 以获得分层 XML 文件 现在 我需要将此 XML 文件绑定到树视图以显示其
  • 使用两个掩码更新数组值 a[mask1][mask2]=value

    给定一个数组和一个掩码 我们可以将新值分配给掩码中为 TRUE 的位置 import numpy as np a np array 1 2 3 4 5 6 mask1 a 2 a 5 a mask1 100 print a 1 100 3
  • 模拟器可以播放什么格式的视频?

    Android模拟器支持哪些格式的视频文件 我知道它可能不会实时播放 但是哪些会实时播放 秘密在于模拟器将播放 MP4 基线配置文件 而真实设备也将播放更好的 MP4 配置文件 为了获得在模拟器中正常播放的视频文件 请尝试以下设置 ffmp
  • 创建下载加速器

    我指的是本文 http www geekpedia com tutorial179 Creating a download manager in Csharp html了解使用 C 下载文件 代码使用传统方法读取Stream就像 bytes
  • MimeKit 将附件添加到从 mht 文件加载的消息中

    您好 我们正在尝试使用 MailKit 开发邮件发送系统 我们有一组使用 WORD 创建并保存为 MHTML 文件的电子邮件模板 当我们使用 MailKit 从 MHT 文件创建 MimeMessage 时 整个事情工作正常 但是在创建此消
  • 同时使用@Document和@Entity

    我尝试在同一个实体类上使用 Document和 Entity 但是当我实现两个存储库 ElasticSearchRepository和CrudRepository 时出现以下错误 The bean esRepo defined in nul
  • 如何更改禁用输入的字体颜色?

    我需要更改 CSS 中禁用的输入元素的样式
  • postgres 函数:IMMUTABLE 何时会损害性能?

    The Postgres 文档 http www postgresql org docs 9 2 static xfunc volatility html say 为了获得最佳优化结果 您应该使用对其有效的最严格的波动性类别来标记您的函数