Я бы предложил изменить таблицу product_prices
, чтобы вместо нее использовать столбец daterange
(или, по крайней мере, start_date
и end_date
).
Вы можете использовать ограничение исключения, чтобы убедиться, что у вас никогда не будет перекрывающихся диапазонов для одного продукта, и триггер вставки, который «закрывает» «текущие» цены и создает новый неограниченный диапазон для вновь вставленной цены.
A daterange
может быть эффективно проиндексирован, и с этим на месте запрос становится таким простым:
SELECT name, product, pu.date, pp.valid_during, pp.price
FROM purchases AS pu
LEFT JOIN product_prices AS pp ON pu.date <@ pp.valid_during
(при условии, что столбец диапазона назван valid_during
)
Ограничение исключения сработало бы, однако, только если продукт был целым числом (не varchar) - но я предполагаю, что ваша настоящая таблица product_purchases
использует внешний ключ для некоторой таблицы продуктов в любом случае (который является целым числом).
Новые определения таблиц могут выглядеть примерно так:
create table purchase_prices
(
product_id integer not null references products,
price numeric(16,4) not null,
valid_during daterange not null
);
И ограничение, которое предотвращает перекрывающиеся диапазоны:
alter table purchase_prices
add constraint check_price_range
exclude using gist (product_id with =, valid_during with &&);
Ограничение требует btree_gist расширение.
Как всегда, повышение скорости запросов сопровождается ценой, и в этом случае это более высокие затраты на обслуживание индекса GiST.Вам нужно будет выполнить некоторые тесты, чтобы увидеть, перевешивает ли более простой (и, скорее всего, гораздо более быстрый) запрос медленную производительность вставки на purchase_prices
.