SQL Server如何实现group by子句(聚合)?
作为灵感,采取这个问题的查询的执行计划:
select p_id, DATEDIFF(D, MIN(TreatmentDate), MAX(TreatmentDate)) from
patientsTable group by p_id
Run Code Online (Sandbox Code Playgroud)
在查询数据之前,简单的select语句及其执行计划是这样的:
使用查询和执行计划检索数据后:
Qua*_*noi 22
通常它是a Stream Aggregate
或a 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
Run Code Online (Sandbox Code Playgroud)
首先,它需要对值进行排序:
grouper value
1 4
1 3
1 7
1 2
2 8
2 1
2 6
2 3
Run Code Online (Sandbox Code Playgroud)
然后,它保留一组状态变量,初始化为0
,并扫描排序的结果集:
石斑鱼值总和计数 - 输入 - 变量: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
Run Code Online (Sandbox Code Playgroud)通常,如果结果集已经排序,则排序更快(例如,值来自索引或由前一操作排序的结果集).
散列更快是结果集未排序(散列比排序更快).
MIN
并且MAX
是特殊情况,因为它们不需要扫描整个组:只有组内聚合列的第一个和最后一个值.
不幸的是,SQL Server
与大多数其他系统不同,它不能有效地利用它,因为它做得不好INDEX SKIP SCAN
(跳过不同的索引键).
而简单MAX
和MIN
(没有GROUP BY
子句)使用TOP
方法,如果所聚集的列的索引的存在,MIN
并MAX
与GROUP BY
使用相同的方法,其它集合函数做.
归档时间: |
|
查看次数: |
4087 次 |
最近记录: |