聚合(分组)如何在SQL Server上工作?

时间:2009-09-24 11:41:05

标签: sql sql-server

SQL Server如何实现group by子句(聚合)?

作为灵感,请采用this question's查询的执行计划:

select p_id, DATEDIFF(D, MIN(TreatmentDate), MAX(TreatmentDate)) from 
patientsTable group by p_id

在查询数据之前,简单的select语句及其执行计划是这样的: alt text

使用查询和执行计划检索数据后: alt text

2 个答案:

答案 0 :(得分:21)

通常是Stream AggregateHash Aggregate

  • Stream aggregate对结果集进行排序,扫描并返回每个新值(不等于扫描中的最后一个值)。它允许保留一组聚合状态变量。

  • Hash aggregate从结果集构建哈希表。每个条目都保留聚合状态变量,这些变量在散列未命中时初始化,并在散列命中时更新。

让我们看看AVG是如何运作的。它需要两个状态变量:sumcount

grouper  value
1        4
1        3
2        8
1        7
2        1
1        2
2        6
2        3

Stream Aggregate

  1. 首先,它需要对值进行排序:

    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 - 结束

  2. 哈希聚合

    • 只需扫描值并将状态变量保留在哈希表中:

      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
      

    通常,如果结果集已经排序,则排序更快(例如,值来自索引或由前一操作排序的结果集)。

    散列更快是因为结果集未排序(散列比排序更快)。

    MINMAX是特殊情况,因为它们不需要扫描整个组:只有组内聚合列的第一个和最后一个值。

    不幸的是,与大多数其他系统不同,SQL Server无法有效利用此功能,因为它不能很好地执行INDEX SKIP SCAN(跳过不同的索引键)。

    虽然简单MAXMIN(没有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的第一顺序,然后分组和差异计算将发生..