Параметры в CTE

Имеется партиционированная таблица table по датам.

Есть запрос, в который в блок CTE подаем даты в виде параметров и вычисляем рабочий день, который затем используем в основном запросе:

  WITH prm 
   AS (
      SELECT 
       :dateFrom::DATE AS d_f, 
       :dateTo::DATE d_t, 
       (SELECT wrk_day d_f_wrk FROM calendar WHERE on_date=:dateFrom)
      )
   SELECT * FROM prm,tab t WHERE t.open_date BETWEEN prm.d_f_wrk AND prm.d_t

Так вот, если используем в основном запросе в условии

BETWEEN prm.d_f_wrk AND prm.d_t

то идет поиск по всем партициям. В плане запроса в фильтре пишется так

t.open_date>=$2 AND t.open_date<='2024-10-30'::DATE

Если же использовать

BETWEEN prm.d_f AND prm.d_t

то фильтруются только нужные партиции. В плане запроса в фильтре пишется так

t.open_date>='2024-10-01'::DATE AND t.open_date<='2024-10-30'::DATE

Как можно передать из CTE или другим способом в основной запрос вычисленную дату в виде такого же параметра даты, чтобы фильтр по партициям отфильтровал только нужные?

Еще дополнение, в принципе не работает фильтр по партициям, если дата берется из другого запроса, то планер бежит по всем партициям

> EXPLAIN analyze SELECT * 
FROM calendar wc, tab t 
WHERE t.open_date =wc.wrk_day  
 AND wc.on_date ='2024-10-30'
 
QUERY PLAN                                                                                                                                       |
-------------------------------------------------------------------------------------------------------------------------------------------------+
Hash JOIN  (cost=2.38..9602.67 ROWS=1099 width=85) (actual TIME=85.080..89.473 ROWS=41 loops=1)                                                  |
  Hash Cond: (t.open_date = wc.wrk_day)                                                                                                |
  ->  Append  (cost=0.00..8758.21 ROWS=316133 width=69) (actual TIME=0.590..54.404 ROWS=315957 loops=1)                                          |
        ->  Seq Scan ON t_2024_02_01 t_1  (cost=0.00..0.00 ROWS=1 width=596) (actual TIME=0.060..0.061 ROWS=0 loops=1)           |
        ->  Seq Scan ON t_2024_02_02 t_2  (cost=0.00..0.00 ROWS=1 width=596) (actual TIME=0.012..0.012 ROWS=0 loops=1)           |
        ->  Seq Scan ON t_2024_02_03 t_3  (cost=0.00..0.00 ROWS=1 width=596) (actual TIME=0.008..0.008 ROWS=0 loops=1)           |
        ->  Seq Scan ON t_2024_02_04 t_4  (cost=0.00..0.00 ROWS=1 width=596) (actual TIME=0.007..0.007 ROWS=0 loops=1)           |
...
...
->  Hash  (cost=2.37..2.37 ROWS=1 width=16) (actual TIME=0.021..0.021 ROWS=1 loops=1)                                                         |
        Buckets: 1024  Batches: 1  Memory Usage: 9kB                                                                                            |
        ->  INDEX Scan USING calendar_pkey ON calendar wc  (cost=0.15..2.37 ROWS=1 width=16) (actual TIME=0.008..0.009 ROWS=1 loops=1)|
              INDEX Cond: (on_date = '2024-10-30'::DATE)

Если в условии явно указать дату, то выбираются нужные партиции

EXPLAIN analyze 
SELECT * 
FROM calendar wc, tab t 
WHERE t.open_date=wc.wrk_day  
 AND wc.on_date ='2024-10-30' AND t.open_date>='2024-10-29' AND t.open_date<'2024-11-01'
 
QUERY PLAN                                                                                                                                      |
------------------------------------------------------------------------------------------------------------------------------------------------+
Hash JOIN  (cost=2.38..33.53 ROWS=3 width=85) (actual TIME=0.037..0.320 ROWS=41 loops=1)                                                        |
  Hash Cond: (t.open_date = wc.wrk_day)                                                                                               |
  ->  Append  (cost=0.00..28.90 ROWS=845 width=69) (actual TIME=0.012..0.225 ROWS=845 loops=1)                                                  |
        ->  Seq Scan ON t_2024_10_29 t_1  (cost=0.00..1.61 ROWS=41 width=69) (actual TIME=0.011..0.016 ROWS=41 loops=1)         |
              FILTER: ((open_date >= '2024-10-29'::DATE) AND (open_date < '2024-11-01'::DATE))                                            |
        ->  Seq Scan ON t_2024_10_30 t_2  (cost=0.00..1.87 ROWS=58 width=69) (actual TIME=0.005..0.011 ROWS=58 loops=1)         |
              FILTER: ((open_date >= '2024-10-29'::DATE) AND (open_date < '2024-11-01'::DATE))                                            |
        ->  Seq Scan ON t_2024_10_31 t_3  (cost=0.00..21.19 ROWS=746 width=69) (actual TIME=0.006..0.135 ROWS=746 loops=1)      |
              FILTER: ((open_date >= '2024-10-29'::DATE) AND (open_date < '2024-11-01'::DATE))                                            |
  ->  Hash  (cost=2.37..2.37 ROWS=1 width=16) (actual TIME=0.015..0.016 ROWS=1 loops=1)                                                         |
        Buckets: 1024  Batches: 1  Memory Usage: 9kB                                                                                            |
        ->  INDEX Scan USING calendar_pkey ON calendar wc  (cost=0.15..2.37 ROWS=1 width=16) (actual TIME=0.012..0.013 ROWS=1 loops=1)|
              INDEX Cond: (on_date = '2024-10-30'::DATE)                                                                                        |
Planning TIME: 0.408 ms                                                                                                                         |
Execution TIME: 0.356 ms                                                                                                                        |
 
15 ROW(s) fetched.

Ответы (1 шт):

Автор решения: Айрат
CREATE OR REPLACE FUNCTION 
work_day(DATE) RETURNS DATE AS $$
SELECT wc.prev_work_day FROM calendar wc WHERE wc.on_date= ($1)::DATE;
$$ LANGUAGE SQL IMMUTABLE;

EXPLAIN analyze
SELECT  *
FROM calendar wc 
LEFT JOIN tab t ON t.open_date=work_day('2024-10-30')
WHERE wc.on_date = '2024-10-30' 

QUERY PLAN

LIMIT  (cost=0.15..4.29 ROWS=41 width=85) (actual TIME=0.018..0.041     ROWS=41 loops=1)                                                             
->  Nested Loop LEFT JOIN  (cost=0.15..4.29 ROWS=41 width=85) (actual     TIME=0.016..0.035 ROWS=41 loops=1)                                      |
->  INDEX Scan USING calendar_pkey ON calendar wc  (cost=0.15..2.37 ROWS=1 width=16) (actual TIME=0.005..0.006 ROWS=1 loops=1)|
      INDEX Cond: (on_date = '2024-10-30'::DATE)                                                                                        |
->  Seq Scan ON tab_2024_10_29 t  (cost=0.00..1.51 ROWS=41 width=69) (actual TIME=0.009..0.017 ROWS=41 loops=1)           |
      FILTER: (open_date = '2024-10-29'::DATE)                                                                                       |
 Planning TIME: 0.325 ms                                                                                                                         |
 Execution TIME: 0.070 ms                                                                                                                        |

 8 ROW(s) fetched.
→ Ссылка