literal vs dynamic partition constraint in plan execution - Mailing list pgsql-general

From Luca Ferrari
Subject literal vs dynamic partition constraint in plan execution
Date
Msg-id CAKoxK+4qyKtzdznxzG+AyOe-Yf=FFbUHRLcptVGK6hrRQD9wPA@mail.gmail.com
Whole thread Raw
Responses Re: literal vs dynamic partition constraint in plan execution
List pgsql-general
Ok, the title is a little buzz, however I've got a partitioned table
and one "leaf" has a set of checks against a timestamp field to ensure
that tuples within such table belongs to the year and month:

testdb=# \d respi.y2019m08
...
Partition of: respi.y2019 FOR VALUES IN ('8')
Check constraints:
    "y2019_mis_ora_check" CHECK (date_part('year'::text, mis_ora) =
2019::double precision)
    "y2019_mis_ora_check1" CHECK (mis_ora >= make_timestamp(2019, 1,
1, 0, 0, 0::double precision) AND mis_ora <= make_timestamp(2019, 12,
31, 23, 59, 59::double precision))
    "y2019m08_mis_ora_check" CHECK (date_part('month'::text, mis_ora)
= 8::double precision)
    "y2019m08_mis_ora_check1" CHECK (date_part('year'::text, mis_ora)
= 2019::double precision)
    "y2019m08_mis_ora_check2" CHECK (mis_ora >= make_timestamp(2019,
8, 1, 0, 0, 0::double precision) AND mis_ora <= make_timestamp(2019,
8, 31, 23, 59, 59::double precision))
    "y2019m08_mis_ora_check3" CHECK (mis_ora >= make_timestamp(2019,
8, 1, 0, 0, 0::double precision) AND mis_ora <= make_timestamp(2019,
8, 31, 23, 59, 59::double precision))

So y2019m08 accepts only tuples where 'mis_ora' has a timestamp that
is contained into the eigth month of the year.
Now if I look at the plan for this query everything works as expected
(I disabled parallel scans for better see the plan):

testdb=# explain select * from respi.root where ts >= '2019-08-28
23:35:00.007245' and mis_ora >= '2019-08-29 16:28:48.711482'   order
by ts;

----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=353986.27..353991.59 rows=2129 width=40)
   Sort Key: y2019m08.ts
   ->  Append  (cost=0.00..353868.58 rows=2129 width=40)
         ->  Seq Scan on y2019m08  (cost=0.00..353409.93 rows=1 width=40)
               Filter: ((ts >= '2019-08-28 23:35:00.007245'::timestamp
without time zone) AND (mis_ora >= '2019-08-29
16:28:48.711482'::timestamp without time zone))
         ->  Seq Scan on y2019m09  (cost=0.00..28.00 rows=133 width=40)
               Filter: ((ts >= '2019-08-28 23:35:00.007245'::timestamp
without time zone) AND (mis_ora >= '2019-08-29
16:28:48.711482'::timestamp without time zone))
         ->  Seq Scan on y2019m10  (cost=0.00..28.00 rows=133 width=40)
               Filter: ((ts >= '2019-08-28 23:35:00.007245'::timestamp
without time zone) AND (mis_ora >= '2019-08-29
16:28:48.711482'::timestamp without time zone))
         ->  Seq Scan on y2019m11  (cost=0.00..28.00 rows=133 width=40)
               Filter: ((ts >= '2019-08-28 23:35:00.007245'::timestamp
without time zone) AND (mis_ora >= '2019-08-29
16:28:48.711482'::timestamp without time zone))
         ->  Seq Scan on y2019m12  (cost=0.00..28.00 rows=133 width=40)
               Filter: ((ts >= '2019-08-28 23:35:00.007245'::timestamp
without time zone) AND (mis_ora >= '2019-08-29
16:28:48.711482'::timestamp without time zone))


The "as I expected" means that the system starts scanning from
y2019m08 and following (in time) tables, and does not scan previous
time tables.
This works if the mis_ora is compared against a literal timestamp, but
if I simply change it with a dynamic timestamp:

testdb=# explain select * from respi.root where ts >= '2019-08-28
23:35:00.007245' and   mis_ora >= current_timestamp   order by ts;
   QUERY PLAN

------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=4654860.37..4654865.25 rows=1952 width=36)
   Sort Key: r.ts
   ->  Nested Loop  (cost=0.00..4654753.69 rows=1952 width=36)
         Join Filter: (r.sen_id = s.sen_id)
         ->  Append  (cost=0.00..4638927.56 rows=3204 width=32)
               ->  Seq Scan on y2018m01 r  (cost=0.00..31.00 rows=133 width=32)
                     Filter: ((ts >= '2019-08-28
23:35:00.007245'::timestamp without time zone) AND (mis_ora >=
CURRENT_TIMESTAMP))
               ->  Seq Scan on y2018m02 r_1  (cost=0.00..31.00
rows=133 width=32)
                     Filter: ((ts >= '2019-08-28
23:35:00.007245'::timestamp without time zone) AND (mis_ora >=
CURRENT_TIMESTAMP))
               ->  Seq Scan on y2018m03 r_2  (cost=0.00..31.00
rows=133 width=32)
                     Filter: ((ts >= '2019-08-28
23:35:00.007245'::timestamp without time zone) AND (mis_ora >=
CURRENT_TIMESTAMP))
               ->  Seq Scan on y2018m04 r_3  (cost=0.00..31.00
rows=133 width=32)
                     Filter: ((ts >= '2019-08-28
23:35:00.007245'::timestamp without time zone) AND (mis_ora >=
CURRENT_TIMESTAMP))

also the tables for the past year are scanned. Moreover, the planner
thinks I will get 133 rows out of, for instance, y2018m01 which is
impossible.
So, do I have defined the constraint on each table in a wrong manner?


testdb=# select version();
                                                 version
---------------------------------------------------------------------------------------------------------
 PostgreSQL 11.5 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5
20150623 (Red Hat 4.8.5-36), 64-bit
(1 row)

testdb=# show constraint_exclusion ;
 constraint_exclusion
----------------------
 partition



Thanks,
Luca



pgsql-general by date:

Previous
From: Gary Cowell
Date:
Subject: Re: Selecting rows having substring in a column
Next
From: Rich Shepard
Date:
Subject: Re: Selecting rows having substring in a column [RESOLVED]