SUM() 比 SQL 中的 SELECT() 花费的时间更少。怎么运行的?

SUM() takes less time than SELECT() in SQL. How it works?

我有一个 SQL table 包含 100 万条记录。当我打电话给

SELECT *
   FROM [AdventureWorksDW2012].[dbo].[LotTable]

完成查询用了 13 秒。

我 运行 下面的查询获取 ID 列的 SUM()。它包含 运行dom 数字,包含正负值。

 SELECT SUM(NewestID)
   FROM LotTable

这个查询只用了 500 毫秒。要执行 SUM() SQL 引擎应该读取值并对其应用一些操作。但是如何运行比SELECT()快。背后的逻辑是什么?提前参考以下images.Thanks。

简答(从DBA的角度):

这是因为 SELECT * 必须 return 比 SELECT SUM(NewestID) 更多的列和行。

此外,SUM() 可能 运行 是并行的,这就是它可能更快的原因。

此外,SSMS 中显示的结果集非常慢,为了比较查询的实际执行时间,您可以在会话开始时使用 SET STATISTICS TIME ON。所以,

SET STATISTICS TIME ON

SELECT *
FROM [AdventureWorksDW2012].[dbo].[LotTable]

SELECT SUM(NewestID)
FROM [AdventureWorksDW2012].[dbo].[LotTable]

现在转到 Messages 选项卡并查看查询的执行时间:

  • CPU 时间:在 CPU 上进行的运算,如聚合(SUMAVG 等)或其他算术运算
  • 经过时间:CPU时间+存储在RAM中、通过内存总线、网络等发送结果所需的时间

您可以尝试的另一件事是放弃在 SSMS 中显示结果。转到工具 -> 选项 -> 查询结果 -> SQL 服务器 -> 结果到网格并检查 "Discard results after execution".

打开一个新选项卡并再次 运行 您的查询,看看它们的执行时间现在如何比较。 (确保取消选中该选项,以便在新会话的其他选项卡中返回结果)。


实际上,可能有比这些更多的因素,例如,如果您在 NewestID 列上有一个索引,或者您是否有(或没有)在 table 上的聚集索引。

这是预期的行为。你会看到当你向数据库系统发送查询时会发生几件事:

  • 分析、优化查询并设计执行模式,
  • 查询已执行 (!),
  • 将结果传达给客户 (!)

最后两项(带有感叹号)是加速的潜在来源。

首先,如果您总结 个值,您不需要存储所有这些值。事实上,您使用了一个 累加器 。所以一个成熟的数据库系统会用值 0 初始化一个累加器,然后对于它找到的每一行(匹配可选约束),它会将该值添加到累加器。关键是,累加器使用固定数量的内存。例如对于一个整数,通常小于 10 个字节。所以累加器存储在(快速)内存中。

SUM(..) 的一个优点还在于它是关联的:((a+b)+c)+d 等于 (a+b)+(c+d)。根据数据库的工作和配置方式,它可以将任务分配给几个工作人员,每个工作人员计算 table 的一部分的总和。然后将这些小数加在一起。

另一方面,如果您执行 SELECT 查询,结果将逐行写入。结果是 linear 内存使用:对于匹配的每一行,我们都需要内存。对于大 tables,旧行可能 "swapped" 不在 CPU 缓存中,有时甚至不在内存中。所以执行查询的时间会更长。

系统终于要响应了。现在,如果您执行 SUM(..),那只有 一行 。所以传输的数据量很小。 SELECT 查询通常会传输数百行。当然,传输大量数据比传输少量数据需要更多时间。

因为您只使用了 1 个字段和一个函数