mysql - 是否可以索引运行总计以加快窗口功能?
问题描述
我想执行:
SELECT cust_id, SUM(cost)
FROM purchases
WHERE purchase_time BETWEEN('2018-01-01', '2019-01-01')
GROUP BY cust_id
但是对于大量行,我希望必须加载每条记录以聚合适当的 SUM。我想要做的是有一个像这样的索引:
CREATE INDEX purchase_sum
ON purchases(cust_id, purchase_time,
SUM(cost) OVER (PARTITION BY cust_id
ORDER BY purchase_time) AS rolling_cost)
我想要一个看起来像这样的索引:
cust_id time rolling_cost
-------- ------ --------------
1 Jan 1 5
1 Jan 2 12
1 Jan 3 14
1 Jan 4 20
1 Jan 5 24
2 Jan 1 1
2 Jan 2 7
2 Jan 3 11
2 Jan 4 14
2 Jan 5 19
3 Jan 1 4
3 Jan 2 5
3 Jan 3 10
3 Jan 4 21
3 Jan 5 45
由此,我的原始查询可以通过简单地为每个 cust_id 减去 2 个已知值来计算,松散地为cost_in_window = rolling_cost('2019-01-01') - rolling_cost('2018-01-01')
,这不需要从源表中加载任何内容。
这可以作为索引吗?还是有另一种方法可以实现相同的目标?
解决方案
您可能会发现这样更快:
select c.cust_id,
(select sum(p.cost)
from purchases p
where p.cust_id = c.cust_id and
p.purchase_time >= '2018-01-01' and
p.purchase_time < '2019-01-01' and
) as total_cost
from customers c
having total_cost is not null;
然后,这可以使用上的索引purchases(cust_id, purchase_time, cost)
。 计算金额只需要索引。那是一种节省。更重要的是,没有整体聚合——这可以节省更多,弥补对所有客户的计算。
但是,使用相同的索引,这可能会好一些:
select c.cust_id,
(select sum(p.cost)
from purchases p
where p.cust_id = c.cust_id and
p.purchase_time >= '2018-01-01' and
p.purchase_time < '2019-01-01'
) as total_cost
from customers c
where exists (select 1
from purchases p
where p.cust_id = c.cust_id and
p.purchase_time >= '2018-01-01' and
p.purchase_time < '2019-01-01'
);
编辑:
实现所需内容的唯一方法是在数据中显式包含累积总和列。这将需要改写查询(进行所需的减法)并使用触发器来维护该值。
如果历史数据从不改变,这可能是一种合理的方法。但是,更新或插入较早的行可能会变得非常昂贵。
推荐阅读
- python - 如何在 pandas DataFrame 中格式化特殊小数
- javascript - 为什么我不能在 JavaScript while 循环之外设置变量的值?
- javascript - 如何阻止把手执行字符串?
- reactjs - 未捕获的 SyntaxError:意外的标记 '<' | 在“纱线添加 xlsx”之后 | 反应打字稿
- flutter - 如何在堆栈内的缩小容器中正确居中文本小部件
- wpf - 设计时错误 Wpf ValidatesOnTargetUpdated NullReferenceException
- android - Kotlin 谷歌地图无法启动
- javascript - VSCODE Javascript模板字符串以不确定的方式变为白色并丢失突出显示
- c# - C# 反序列化 - 获取属性返回 null
- wpf - 如何在 wix 工具集引导程序项目中获取当前的 wpf 项目程序集版本?