为啥当我第二次使用完全相同的参数调用 IMMUTABLE 函数时,计划时间会加倍?

Posted

技术标签:

【中文标题】为啥当我第二次使用完全相同的参数调用 IMMUTABLE 函数时,计划时间会加倍?【英文标题】:Why plainning time is doubled when I call IMMUTABLE function with exatly same arguments second time?为什么当我第二次使用完全相同的参数调用 IMMUTABLE 函数时,计划时间会加倍? 【发布时间】:2021-04-22 19:55:51 【问题描述】:

比较:

在第一种情况下,我用相同的参数调用相同的find_period。因为函数是IMMUTABLE 我想它的计划将被重用(相同的功能,相同的参数,相同的计划),但似乎它没有被重用为什么?

源函数:

CREATE OR REPLACE FUNCTION "find_period" (in _start timestamptz, in _interval interval, in _target timestamptz)
 RETURNS tstzrange
 LANGUAGE sql
 IMMUTABLE RETURNS NULL ON NULL INPUT
 AS $$
    SELECT CASE
    WHEN _interval = INTERVAL '00:00:00' THEN
      tstzrange( _start, _start, '[]' )
    ELSE (
      SELECT CASE WHEN max( date ) = _target
        THEN tstzrange( max( date ) -_interval, max( date ) )
        ELSE tstzrange( max( date ), max( date ) +_interval )
      END
      FROM generate_series( _start, _target, _interval ) t (date )
    ) END
    WHERE _start < _target  OR  _interval = INTERVAL '00:00:00'
$$

并查询:

EXPLAIN ANALYZE SELECT find_period( 
   '2020-04-03',  
   INTERVAL '1day', 
   '9999-01-01' 
)

UPDEXPLAIN ( ANALYZE, buffers, timing ) 第一次调用的缓冲区是 12808 VS 6404 第二次:

db=> select version();
                                                     version                              
------------------------------------------------------------------------------------------
 PostgreSQL 13.1 (Debian 13.1-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian
(1 row)

db=> EXPLAIN ( ANALYZE, buffers, timing ) SELECT find_period( 
   '2020-04-03',  
   INTERVAL '1day', 
   '9999-01-01' 
), find_period( 
db(>    '2020-04-03',  
db(>    INTERVAL '1day', 
db(>    '9999-01-01' 
db(> );
                                     QUERY PLAN                                      
-------------------------------------------------------------------------------------
 Result  (cost=0.00..0.01 rows=1 width=64) (actual time=0.003..0.003 rows=1 loops=1)
 Planning:
   Buffers: temp read=12808 written=12808
 Planning Time: 3215.465 ms
 Execution Time: 0.023 ms
(5 rows)

db=> EXPLAIN ( ANALYZE, buffers, timing ) SELECT find_period( 
db(>    '2020-04-03',  
db(>    INTERVAL '1day', 
db(>    '9999-01-01' 
db(> );
                                     QUERY PLAN                                      
-------------------------------------------------------------------------------------
 Result  (cost=0.00..0.01 rows=1 width=32) (actual time=0.002..0.002 rows=1 loops=1)
 Planning:
   Buffers: shared hit=97, temp read=6404 written=6404
 Planning Time: 1583.670 ms
 Execution Time: 0.017 ms
(5 rows)

【问题讨论】:

@a_horse_with_no_name:图片更新,提供方案,提供版本 【参考方案1】:

与您的预期不同,PostgreSQL 调用该函数两次,因为它不会花费额外的计划工作来检查您是否使用相同的常量两次调用相同的函数。

做合理的事:

SELECT x, x
FROM find_period('2020-04-03', INTERVAL '1day', '9999-01-01' ) AS f(x);

【讨论】:

如果我理解正确:extra planning effort 不值得(尽管它需要额外的 1.5 秒),因为我写了“生病”的查询。如果实施EXPLAIN (ANALYZE HINT) 会报告有关此类错误的提示并可能提示丢失索引等是否会受益? 额外的工作将使许多查询的规划速度变慢,而只有少数查询会受益。那将是净亏损。此外,很容易解决这个问题。你的EXPLAIN (ANALYZE HINT) 听起来不错,但我个人认为还没有人工智能。

以上是关于为啥当我第二次使用完全相同的参数调用 IMMUTABLE 函数时,计划时间会加倍?的主要内容,如果未能解决你的问题,请参考以下文章

当我第二次设置它的 ItemsSource 时,为啥这个选择器会崩溃?

当我第二次实例化预制件时,为啥会出现错误?

为啥我第二次使用侧边菜单打不开? (MMDrawerController + UITabBarController)

为啥我第二次点击 fileReferencer.browse 按钮​​后 TextInput 会更新

为啥 MySQL 查询在我第二次运行时更快?

第二次在图上运行时,广度/深度优先搜索导致崩溃