Вот мой случай:
Я хотел бы рассчитать количество и цену для данного товара на любую дату.
Цены рассчитываются с использованием общего количества товара и цены за единицу, поэтому цена меняется в зависимости от количества товара.
warehouse_1
указывает, что товар был отправлен с этого склада, warehouse_2
указывает, что товар был отправлен на этот склад.
Вот моя логика:
Выборка поставок для каждого товара и суммирование их количества.(1-й CTE)
Найти сумму количеств в обоих складах отдельно.(2nd CTE)
Рассчитайте окончательное количество и умножьте его на цену за единицу.
Показать результат, который состоит из идентификатора товара, количества и цены.
Я написал запрос, который правильно выполняет вычисления, НО он становится экспоненциально медленнее, когда количество данных увеличивается.(Занимает 5 секунд на моей БД с 6 тыс. Строк, почти блокирует БД на моей коллеге с 21 тыс. Строк)
Как я могу оптимизировать этот запрос?Я делаю кумулятивные вычисления для 2-го CTE для каждой строки, поступающей из 1-го CTE, и я считаю, что это требует переделки
Могу ли я использовать функцию LAG()
для этого варианта использования?Я попробовал это с чем-то вроде
LAG(a.deliveryTotal) over(order by a.updated desc rows between unbounded preceding and current row)
вместо блока CASE во втором CTE, но я не могу понять, как использовать filter()
или поместить условие в оператор LAG ().
Вот мой запрос:
`
with deliveriesCTE as (
select
row_number() over(partition by it.id
order by
dd.updated asc) as rn,
sum(dd.quantity) as deliveryTotal,
dd.updated as updated,
it.id as item_id,
d.warehouse_1 as outWH,
d.warehouse_2 as inWH,
d.company_code as company
from
deliveries d
join deliveries_detail dd on
dd.deliveries_id = d.id
join items it on
it.id = dd.item_id
where
...
group by
dd.updated,
it.id,
d.warehouse_1,
d.warehouse_2,
d.company_code
order by
dd.updated asc),
cumulativeTotalsByUnit as (
select
distinct on
(a.item_id) a.rn,
a.deliveryTotal,
a.updated,
a.item_id,
a.outWH,
a.inWH,
a.company,
case
when a.rn = 1
and a.outWH is not null then coalesce(a.deliveryTotal,
0)
else (
select
coalesce(sum(b.deliveryTotal) filter(
where b.outWH is not null),
0)
from
deliveriesCTE b
where
a.item_id = b.item_id
and b.rn <= a.rn)
end as outWHTotal,
case
when a.rn = 1
and a.inWH is not null then coalesce(a.deliveryTotal,
0)
else (
select
coalesce(sum(b.deliveryTotal) filter(
where b.inWH is not null),
0)
from
deliveriesCTE b
where
a.item_id = b.item_id
and b.rn <= a.rn)
end as inWHTotal
from
deliveriesCTE a
order by
a.item_id,
a.updated desc)
select
resultView.item_id,
resultView.quantity,
resultView.price
from
(
select
cumTotals.item_id,
cumTotals.inWHTotal - cumTotals.outWHTotal as quantity,
p.price * (cumTotals.inWHTotal - cumTotals.outWHTotal) as price
from
prices p
join cumulativeTotalsByUnit cumTotals on
cumTotals.item_id = p.item_id ) resultView
where
resultView.rn = 1;
`