SQL Server 如何实现 group by 子句(聚合)?
以this question's的执行计划为灵感询问:
select p_id, DATEDIFF(D, MIN(TreatmentDate), MAX(TreatmentDate)) from
patientsTable group by p_id
在查询数据之前,简单的select语句及其执行计划是这样的:
使用查询和执行计划检索数据后:
最佳答案
通常是 Stream Aggregate
或 Hash Aggregate
.
Stream aggregate
对结果集进行排序、扫描并返回每个新值(不等于扫描中的最后一个值)。它只允许保留一组聚合状态变量。 Hash aggregate
从结果集构建一个哈希表。每个条目都保留在散列未命中时初始化并在散列命中时更新的聚合状态变量。 让我们看看如何
AVG
作品。它需要两个状态变量:sum
和 count
grouper value
1 4
1 3
2 8
1 7
2 1
1 2
2 6
2 3
流聚合
grouper value
1 4
1 3
1 7
1 2
2 8
2 1
2 6
2 3
0
, 并扫描排序后的结果集:石斑鱼值(value)总和计数
-- 进入
-- 变量:0 0
1 4 4 1
1 3 7 2
1 7 14 3
1 2 16 4
——组别。返回结果并重新初始化变量
-- 返回 1、4
-- 变量:0 0
2 8 8 1
2 1 9 2
2 6 15 3
2 3 18 4
——组别。返回结果并重新初始化变量
-- 返回 2, 4.5
-- 完
哈希聚合
grouper value
-- Hash miss. Adding new entry to the hash table
-- [1] (0, 0)
-- ... and updating it:
1 4 [1] (4, 1)
-- Hash hit. Updating the entry:
1 3 [1] (7, 2)
-- Hash miss. Adding new entry to the hash table
-- [1] (7, 2) [2] (0, 0)
-- ... and updating it:
2 8 [1] (7, 2) [2] (8, 1)
1 7 [1] (14, 3) [2] (8, 1)
2 1 [1] (14, 3) [2] (9, 2)
1 2 [1] (16, 4) [2] (9, 2)
2 6 [1] (16, 4) [2] (15, 3)
2 3 [1] (16, 4) [2] (18, 4)
-- Scanning the hash table and returning the aggregated values
-- 1 4
-- 2 4.5
通常,如果结果集已经排序(例如,值来自索引或按前一个操作排序的结果集),则排序会更快。
哈希更快是结果集未排序(哈希比排序快)。
MIN
和 MAX
是特殊情况,因为它们不需要扫描整个组:仅扫描组内聚合列的第一个和最后一个值。不幸的是,
SQL Server
与大多数其他系统不同,不能有效地利用它,因为它不擅长做 INDEX SKIP SCAN
(跳过不同的索引键)。虽然简单
MAX
和 MIN
(没有 GROUP BY
子句)使用 TOP
如果聚合列上的索引存在,则方法,MIN
和 MAX
与 GROUP BY
使用与其他聚合函数相同的方法。
关于sql - 聚合(分组依据)如何在 SQL Server 上工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1471147/