如何让窗口函数不受WHERE过滤,仅返回2月交易但计算全量历史数据
解决方案
核心思路
原写法的问题是WHERE条件先过滤了2月数据,窗口函数只能在过滤后的数据集内计算,因此累计仅包含2月交易。如果先全表执行窗口函数再过滤2月数据,会产生大量冗余计算,在数据量极大的场景下性能极差。
最优解法将累计金额拆分为两部分计算,避免全量明细上的窗口计算:
- 先聚合计算每个用户截止2020年1月31日的历史累计消费,仅需分组聚合无需保留明细,计算量极低
- 仅在2月的小范围明细数据集上执行窗口函数,计算用户2月内的逐笔累计
- 两部分结果相加即可得到历史全量累计
实现代码
WITH hist_cumulative AS ( -- 计算每个用户1月底前的历史总消费 SELECT customer_id, SUM(price) AS hist_total FROM sales WHERE day < DATE '2020-02-01' GROUP BY customer_id ), feb_transactions AS ( -- 仅取2月交易,在小数据集上计算2月内的逐笔累计 SELECT transaction_id, customer_id, SUM(price) OVER (PARTITION BY customer_id ORDER BY day) AS feb_cumulative FROM sales WHERE day BETWEEN DATE '2020-02-01' AND DATE '2020-02-29' ) SELECT f.transaction_id, COALESCE(h.hist_total, 0) + f.feb_cumulative AS total FROM feb_transactions f LEFT JOIN hist_cumulative h ON f.customer_id = h.customer_id ORDER BY f.transaction_id;
注意:你原写法中的WHERE条件日期误写为2021年,需修正为2020年才能匹配示例数据。
性能说明
该方案仅需要扫描「2020年2月及之前的交易数据」,且2月之前的交易仅需按用户分组聚合,不需要执行窗口函数,计算量远低于全表执行窗口后过滤的方案。如果业务侧有预计算的用户累计消费快照表,可直接读取快照替代hist_cumulative的聚合逻辑,无需扫描历史明细,性能可进一步大幅提升。
结果验证
该代码输出和你给出的期望结果完全一致:
| transaction_id | total |
|---|---|
| 5 | 90 |
| 6 | 120 |
| 7 | 160 |
| 8 | 200 |
内容的提问来源于stack exchange,提问作者KOB
相关产品推荐
相关产品推荐

