【问题标题】:Why won't Postgres filter my date range partitions?为什么 Postgres 不过滤我的日期范围分区?
【发布时间】:2017-10-16 13:38:52
【问题描述】:

我有一张表,它使用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(反正我不需要)。我添加了一个以防万一,但它没有帮助。

为什么会发生这种情况,我可以做些什么来阻止它(最好不要给简单的查询增加复杂性)?

【问题讨论】:

  • Edit您的问题并为有问题的表(包括所有索引)添加create table语句以及使用explain (analyze, verbose)生成的执行计划Formatted textno screen shots
  • 那是因为 planner 直到执行才知道 now() 的输出。
  • 谢谢@JustMe - 你能把这个作为答案发布,这样我就可以接受它并删除不必要的 SQL 和 EXPLAIN 的输出,这样也可以帮助其他人?

标签: postgresql database-partitioning


【解决方案1】:

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

问题在于何时根据FROM 评估NOW()CURRENT_TIMESTAMP;当您尝试过滤加入 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... 来进行测试

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多