当作为参数传递给函数时,now()如何得到评估

时间:2018-04-01 14:27:07

标签: postgresql postgresql-10 query-planner

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

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())

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

1 个答案:

答案 0 :(得分:1)

这里有几个问题;我会尽力回答所有问题。

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

如果以now()为参数调用函数,则会在函数调用时对其进行求值。

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

  1. PostgreSQL决定在第五次执行查询后切换到通用计划。然后就不会进行分区修剪。

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

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

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