为什么赢得Postgres过滤我的日期范围分区?

时间:2017-10-16 13:38:53

标签: postgresql database-partitioning

我有一个表使用declarative partitioning(w00t!)按日期范围对表进行分区 - 在我的情况下为一年。

当我查询表格SELECT * FROM tbl WHERE date > date '2016-01-01'时,它完全符合预期;只扫描包含较新数据的表格。

当我使用变量或函数(CURRENT_DATENOW()等)指定日期时,EXPLAIN表示会扫描每个分区。

按预期工作的事情:

SELECT * FROM tbl WHERE date > date '2016-01-01'
--
SELECT * FROM tbl WHERE date > '2016-01-01'::date

不必要地扫描所有分区的事情:

SELECT * FROM tbl WHERE date > CURRENT_DATE
--
SELECT * FROM tbl WHERE date > NOW()
--
SELECT * FROM tbl WHERE date > (NOW() - 365)::date
--
SELECT * FROM tbl WHERE date > (SELECT (NOW()::date - 365)::date AS d)
-- Even CTEs are no dice:
WITH a AS (SELECT CURRENT_DATE AS d)
SELECT * FROM tbl, a WHERE date > a.d
-- Same with JOINs
SELECT w.*
FROM (CURRENT_DATE - 365 as d) a
LEFT JOIN wtf w ON w.date > a.d

...等

我与其他比较运算符=<等有相同的行为。

文档说我不需要场上的idx(我不会反正)。我添加了一个以防万一,它没有帮助。

为什么会发生这种情况,我该怎么做才能阻止它(最好不要在简单的查询中添加复杂功能)?

1 个答案:

答案 0 :(得分:2)

感谢JustMe回答这个问题 - 请参阅OP上的评论。

问题在于NOW()CURRENT_TIMESTAMPFROM相关的评估时间;当您尝试在联接ala WHERE join_table.a > from_table.b中过滤时,您会看到同样的问题。

假设今天是1970年1月1日,这些查询

SELECT * FROM my_stuff WHERE date > NOW()::date;
--
SELECT * FROM my_stuff WHERE date > '1970-01-01'::date;

必然会产生相同的结果集,但不一定以相同的方式进行评估。

这就是为什么会发生这种情况,不幸的是,似乎没有一种简单的方法可以阻止它。功能似乎是最好的选择:

CREATE OR REPLACE FUNCTION myfunc()
    RETURNS setof tbl
    LANGUAGE 'plpgsql'
AS $$
DECLARE
    n date := CURRENT_DATE - 365;
BEGIN
    RETURN query EXECUTE $a$
        SELECT * FROM tbl
        WHERE date > $1;
    $a$ using n;
END $$;

您可以通过将RETURNS setof tbl更改为RETURNS setof text并将SELECT...更改为EXPLAIN SELECT...

来对此进行测试
相关问题