sum - 如何使用 SQL Server SUM 函数避免指数时间成本?
问题描述
我意识到每次使用 SUM 函数时我的查询都需要指数级的时间......
例如,下面的代码需要 2 秒
SELECT sub.a, SUM(sub.b)
FROM (
SELECT a, b, c
FROM temp
)sub
GROUP BY a;
现在使用第二个 SUM 需要 4 秒,依此类推......
SELECT sub.a, SUM(sub.b), SUM(sub.c)
FROM (
SELECT a, b, c
FROM temp
)sub
GROUP BY a;
似乎我所做的每个 SUM 都会再次执行子查询,这是否正确,避免时间成本的最佳做法是什么?
上面的例子只是以最基本的方式表示问题
解决方案
TL;DR:不,这是完全错误的。
当您在 SQL Server 中运行查询时,优化器会将其编译成它可以找到的最有效的方法。您可以通过单击Include Actual Execution Plan
SSMS 来查看结果。
对于您指定的查询,它通常会执行以下操作:
- 它指出子查询可以内联到查询中,并且这样做:
SELECT sub.a, SUM(sub.b), SUM(sub.c)
FROM temp
GROUP BY a;
然后它评估按
a
值聚合表的最佳方法。假设根本没有索引,Hash Aggregate
这里很可能会选择 a。在执行时,每一行都被输入到 Hash 中,它建立了一个内存中的哈希表,其中
a
值作为键。每一行都基于 查找a
,如果之前没有看到过,则将一个键添加到哈希表中。然后将值添加b
到c
该键。假设您在
a,b,c
. 现在可以使用更快的方法,称为 Stream Aggregate,因为现在值正在通过按 排序的 Aggregatea
。每行都通过聚合。如果该
a
值与之前的行相同,则将其b
和c
值添加到我们目前所拥有的任何内容中。当a
值发生变化时,输出现有结果,我们再次开始聚合。
确实,对额外的列求和是额外的开销,但与读取磁盘表或散列表相比,它非常小,每个查询只执行一次。
推荐阅读
- applescript - 如何将 Apple Mail 收到的日期、月份转换为字符串或数字?
- c++ - 传递给函数时转换参数(c ++)
- javascript - XMLHttpRequest 到没有 URL 参数的站点
- stm32 - STM32示例中变量名开头的“uw”是什么意思?
- google-compute-engine - 如何在 GCE - Google Compute Engine 上获取特定实例组的外部 IP?
- ruby - 为什么表达式“Object.singleton_class.instance_method(:refine)”会引发“NameError”?
- c# - C# 线程 - 主线程卡在 inf 循环中
- react-native - Expo 是否需要 Internet 连接才能进行 React 本机构建?
- tensorflow - 如何确定我的机器学习脚本的最佳 GPU 数量?
- java - 为什么for循环可以初始化Java中按值传递的变量