i有一个表格在时间戳上分区的表格。我很惊讶地发现,以下条件导致计划者在分区中查询每个"孩子"表:
WHERE reading_time > (now() - '72:00:00'::interval)
我了解到,计划者不知道现在((在执行时会是什么,因此它生成了查询每个子表的计划。这是可以理解的,但这首先是设置分区的目的!如果我发布了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仅查询适当的子表,对吗?但是,如果现在正在评估该功能内部((,那么我会回到扫描每个子表索引的计划。似乎没有什么容易看到计划者在功能中所做的事情。这是正确的吗?
这里有几个问题;我会尽力回答所有这些。
PostgreSQL无法在计划时评估now()
,因为无法知道何时执行语句。计划可以无限的时间保存。
如果将now()
称为参数的函数,将在函数调用时进行评估。
如果您在涉及函数内的分区表的SQL语句中使用参数(因此,计划被缓存(,则可能发生两件事:
-
PostgreSQL决定在查询第五次执行后切换到通用计划。然后不可能进行分区修剪。
-
PostgreSQL决定坚持自定义计划,以便进行分区修剪。
一个人通常会选择第二个选项,但是要找出您可以使用auto_explain
查看实际使用的计划。
使用动态SQL可能是一个好主意,以便始终将查询重新粘贴到当前参数值中,并且可以使用分区修剪。