将 now() 作为参数传递给函数时如何进行评估

Posted

技术标签:

【中文标题】将 now() 作为参数传递给函数时如何进行评估【英文标题】:How does now() get evaluated when passed into a function as a parameter 【发布时间】:2018-04-01 14:27:07 【问题描述】:

我有一个表,该表在时间戳和时区字段上进行范围分区。我很惊讶地发现以下 where 条件导致规划器查询分区中的每个“子”表:

WHERE reading_time > (now() - '72:00:00'::interval)

据我所知,计划器不知道 now() 在执行时会是什么,因此它会生成查询每个子表的计划。这是可以理解的,但这违背了设置分区的初衷!如果我发出 reading_time > '2018-03-31',它只会对具有满足这些条件的数据的表进行索引扫描。

如果我创建以下函数会发生什么

CREATE OR REPLACE FUNCTION public.last_72hours(in_time timestamp with time zone)

   Select * from precip where reading_time > (in_time - '72:00:00'::interval)
   --the function will then do work on the returned rows

END;

然后我可以调用函数

SELECT last_72hours(now())

now() 何时被评估?或者,换句话说,是否将文字时间值(例如,2018-03-31 1:01:01+5)传递到函数中?如果是字面值,那么 Postgres 只会查询相应的子表,对吧?但是,如果它在函数内部评估 now(),那么我将回到扫描每个子表索引的计划。似乎很难看到计划者在函数中做了什么。对吗?

【问题讨论】:

【参考方案1】:

这里有几个问题;我会尽力一一解答。

PostgreSQL 无法在计划时评估now(),因为无法知道语句何时执行。计划可以无限期保留。

如果您以now() 作为参数调用函数,它将在函数调用时进行评估。

如果您在涉及函数内部分区表的 SQL 语句中使用参数(因此计划被缓存),可能会发生两种情况:

    PostgreSQL 决定在第五次执行查询后切换到通用计划。那么就不能进行分区修剪了。

    PostgreSQL 决定坚持使用自定义计划,以便进行分区修剪。

人们会假设通常会选择第二个选项,但要找出答案,您可以使用auto_explain 查看实际使用的计划。

使用动态 SQL 可能是个好主意,以便始终使用当前参数值重新计划查询,并且肯定会使用分区修剪。

【讨论】:

感谢您抽出宝贵时间回复。因此,只需在我的 PL/pgSQL 函数开头附近使用以下内容就足够了:execute 'select now() ' into intime;? 不,这不会产生影响,因为在计划时该值也是未知的。您应该使用动态 SQL (EXECUTE) 以确保从不使用通用计划,并且您始终受益于分区的约束排除。

以上是关于将 now() 作为参数传递给函数时如何进行评估的主要内容,如果未能解决你的问题,请参考以下文章

当我们将数组作为参数传递给其他函数时,数组的值如何变化? [复制]

AngularJS:如何将参数/函数传递给指令?

如何将两个参数传递给 Pool.starmap()?

当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?

将Datetime作为参数传递给PyODBC的存储过程时出错

如何在一个条目中将RGB作为单独的参数传递给函数