SQL Server如何实现group by子句(聚合)?
作为灵感,请采用this question's查询的执行计划:
select p_id, DATEDIFF(D, MIN(TreatmentDate), MAX(TreatmentDate)) from
patientsTable group by p_id
在查询数据之前,简单的select语句及其执行计划是这样的:
使用查询和执行计划检索数据后:
答案 0 :(得分:21)
通常是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
,并扫描排序的结果集:
石斑鱼价值总和计数 - 进入 - 变量: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
和{ {1}} MAX
使用与其他聚合函数相同的方法。
答案 1 :(得分:0)
我没有桌子,我试过我的自定义桌子PRICE
我定义了主键= ID_PRICE
Select PRICE.ID_PRICE, Max(PRICE.COSTKVARH) - min(PRICE.COSTKVARH) from PRICE
GROUP BY PRICE.ID_PRICE
安排:
计划(价格订单PK_PRICE)
改编计划:
计划(价格订单PK_PRICE)
在你的情况下,p_id是一个主键,因此适应的计划将是基于p_id的PatientTable的第一顺序,然后分组和差异计算将发生..