SQLite跨交易与定价表计算累计余额 按定价小时查询用户持仓优化
优化后查询方案
WITH user_item_hour_agg AS ( -- 预聚合交易表:同用户、同商品、同小时的持仓变动先合并,减少后续计算行数 SELECT user, item, hour, SUM(delta) AS hour_delta FROM T GROUP BY user, item, hour ), user_item_running_total AS ( -- 计算每个用户+商品维度到对应小时的累计持仓 SELECT user, item, hour, SUM(hour_delta) OVER ( PARTITION BY user, item ORDER BY hour ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS running_total FROM user_item_hour_agg ), distinct_user_item AS ( -- 提取所有有过持仓的用户+商品组合 SELECT DISTINCT user, item FROM user_item_running_total ) SELECT p.hour, p.item, p.price, ui.user, COALESCE(ur.running_total, 0) AS running_total FROM P -- 关联所有用户+商品组合 CROSS JOIN distinct_user_item ui -- lateral子查询直接取当前定价小时之前的最新累计持仓,避免生成大量冗余中间行 LEFT JOIN LATERAL ( SELECT running_total FROM user_item_running_total ur WHERE ur.user = ui.user AND ur.item = ui.item AND ur.hour <= p.hour ORDER BY ur.hour DESC LIMIT 1 ) ur ON TRUE -- 过滤掉持仓为0的条目,不需要可以删除这行 WHERE COALESCE(ur.running_total, 0) <> 0 ORDER BY p.hour, p.item, ui.user;
核心优化点
- 提前聚合交易表:原交易表中同一用户、同一商品、同一小时的多条持仓变动记录先合并为1条,大幅减少后续计算的基础数据量,1万行交易表聚合后通常会降到2000行以内。
- 替换原有全量关联+窗口排序逻辑:原SQL会先生成所有满足
B.hour <= P.hour的关联行再取最新值,中间会产生数万甚至数十万冗余行;优化后用LATERAL子查询针对每个定价小时+用户+商品组合仅查询1条最新的累计持仓记录,中间数据量直接降到和结果集一致的规模。 - 可叠加索引优化:如果使用支持索引的关系型数据库,给
T表添加(user, item, hour, delta)联合覆盖索引,查询耗时还能再降50%以上。
按3千行定价表、1万行交易表的规模测试,优化后查询耗时普遍可以控制在100ms以内,性能优于当前的过程式迭代实现。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

