我有一个在时间戳上使用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(),那么我将回到扫描每个子表的索引的计划。看起来很难看出规划师在这个功能中做了些什么。这是对的吗?
答案 0 :(得分:1)
这里有几个问题;我会尽力回答所有问题。
PostgreSQL无法在计划时评估now()
,因为无法知道语句何时执行。计划可以无限期保留。
如果以now()
为参数调用函数,则会在函数调用时对其进行求值。
如果在涉及函数内部分区表的SQL语句中使用参数(因此计划被缓存),可能会发生两件事:
PostgreSQL决定在第五次执行查询后切换到通用计划。然后就不会进行分区修剪。
PostgreSQL决定坚持使用自定义计划,以便进行分区修剪。
人们会假设通常会选择第二个选项,但要找出你可以使用auto_explain
来查看实际使用的计划。
使用动态SQL可能是个好主意,以便始终使用当前参数值重新计划查询,并且肯定会使用分区修剪。