查找具有条件和分组的累计总数

问题描述 投票:0回答:1

这是我的情况:

我想在任何给定日期计算给定项目的数量和价格。

价格使用总项目数量和单位价格计算,因此价格会根据项目的数量而变化。

warehouse_1表示该物品是从该仓库发货的,warehouse_2说该物品已送到该仓库。

这是我的逻辑:

获取每个项目的交货并汇总其数量。 (第一届CTE)

分别查找两个仓库中的数量总和。 (第二届CTE)

计算最终数量并乘以单价。

显示由商品ID,数量和价格组成的结果。

我写了一个查询,它正确地进行了计算,但是当数据计数变大时,它会以指数方式变慢。 (在我的数据库上用6k行占用5秒,几乎将DB锁定在我的同事的DB上,行数为21k)

如何优化此查询?我正在对来自第一次CTE的每一行的第二次CTE进行累积计算,我认为这需要返工。

我可以在这个用例中使用LAG()函数吗?我尝试过类似的东西

LAG(a.deliveryTotal) over(order by a.updated desc rows between unbounded preceding and current row)

而不是第二次CTE中的CASE块,但我似乎无法弄清楚如何使用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;

`

sql postgresql query-performance
1个回答
1
投票

如果没有MCV,很难说,但我对你要做的事情的猜测是做一个Windowed SUM()计算而不是LAG()。有文档Here

查询cumulativeTotalsByUnit不应该是必需的,并且可能是二次的,以进行复杂的自引用连接。

您的交付CTE应如下所示:

select
    sum(dd.quantity) over (partition by it.id ORDER BY dd.updated asc) 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
© www.soinside.com 2019 - 2024. All rights reserved.