Планировщик не использует проверку ограничений

Пожалуйста, рассмотрите следующие объекты:

create table invoices_2011 (
  invoice_id bigint not null,
  invoice_date date not null,
  constraint invoice_line_2011_ck1 CHECK (invoice_date >= '2011-01-01' AND 
      invoice_date < '2012-01-01')
);

create table invoices_2012 (
  invoice_id bigint not null,
  invoice_date date not null,
  constraint invoice_line_2012_ck1 CHECK (invoice_date >= '2012-01-01' AND
      invoice_date < '2013-01-01')
);

create table invoices_2013 (
  invoice_id bigint not null,
  invoice_date date not null,
  constraint invoice_line_2013_ck1 CHECK (invoice_date >= '2013-01-01' AND
      invoice_date < '2014-01-01')
);

create or replace view invoices as
select * from invoices_2011
union all 
select * from invoices_2012
union all 
select * from invoices_2013;

Если я смотрю на план объяснения для следующего запроса:

select * from invoices where invoice_date > '2013-10-01';

Это указывает на то, что единственная фактическая физическая таблица для сканирования - это invoices_2013, чего я и ожидал.

Однако, когда я смотрю на план объяснения для этого запроса (сегодня 10/11/13):

select * from invoices where invoice_date > date_trunc ('month', current_date)

Сканирует все три таблицы.

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

1 ответ

Решение

Проблема в том, что where пункт должен соответствовать check constraint, Как ни date_trunc() ни current_date являются неизменяемыми, они не будут "встроенными" в запросе, что означает, что оценка этих функций будет происходить только во время выполнения запроса, после фазы планирования запроса, и поэтому планировщик не будет знать, соответствует ли условие check constraint

Чтобы предоставить планировщику необходимую информацию, запрос должен быть построен динамически

create or replace function select_from_invoices(
    _d date
) returns setof invoices as $body$

begin

return query execute $$
    select *
    from invoices
    where invoice_date > $1
    $$
    using date_trunc('month', _d)
;

end;
$body$ language plpgsql;

Теперь запрос будет планироваться только после результата date_trunc присоединяется к строке запроса.

Выполните это:

select *
from select_from_invoices(current_date);
Другие вопросы по тегам