2017-10-16 70 views
0

我有一个使用declarative partitioning表进行分区按日期范围表(w00t!) - 在我的情况一年。为什么Postgres不会过滤我的日期范围分区?

当我查询对阵表 - SELECT * FROM tbl WHERE date > date '2016-01-01',它的工作原理完全如预期;只扫描包含较新数据的表格。

当我使用变量或函数(CURRENT_DATE,NOW()等)指定日期时,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(我不反对)。我添加了一个以防万一,并没有帮助。

为什么会这样,我能做些什么来阻止它(最好是不添加复杂到简单的查询)?

+0

请** [编辑] **你的问题,并添加'创建表'所讨论的表的语句(包括所有索引)以及使用**'explain(analyze,verbose)'**生成的执行计划。 [**格式化文本**](http://stackoverflow.com/help/formatting)请,[无屏幕截图](http://meta.stackoverflow.com/questions/285551/why-may-i-not当问问题/ 285557#285557) –

+2

这是因为规划师不知道now()的输出,直到执行。 – JustMe

+0

谢谢@JustMe - 你会发布这个作为答案,所以我可以接受它,并删除不必要的SQL和输出的解释,所以这可以帮助其他人呢? – onwsk8r

回答

0

感谢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; 

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

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

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 tblRETURNS setof textSELECT...测试以EXPLAIN SELECT...