以前系列中在查询计划中一直出现Stream Aggregate,当时也只是作了基本了解,对于查询计划中出现的操做,咱们都须要去详细研究下,只有这样才能对查询计划执行的每一步操做都了如指掌,因此才有了本文的出现,简短的内容,深刻的理解,Always to review the basics。函数
Stream Aggregate经过单列或者多列来对行进行分组而且对指定的查询来计算聚合表达式。最多见的聚合类型如SUM、COUNT、SUM、AVG、MIN、MAX,当咱们执行这些聚合函数时在查询计划中就会出现Stream Aggregate,Stream Aggregate是很是快的,由于它须要在输入时经过在GROUP BY中指定的列进行排序。若是聚合中的数据没有进行排序此时会经过Sort进行预排序或者使用索引查找或者索引扫描来提早预排序数据。以前咱们讨论过出现Stream Aggregate有三种方式分别为:聚合函数聚合,分组聚合,DISTINCT聚合,实际上只有两种,DISTINCT内部就用到了分组,这里咱们将Stream Aggregate分为两种类型,一种是标量聚合,另一种则是分组聚合。咱们举一个标量聚合的例子,也就是返回单值聚合。性能
USE TSQL2012 GO SELECT COUNT(*) FROM Sales.Orders
下面咱们再来分组聚合的例子优化
USE TSQL2012
GO
SELECT custid
FROM Sales.Orders
GROUP BY custid
上述就是Stream Aggregate两种类型的例子,关于标量聚合比较简单直接利用聚合函数就行,下面咱们主要详细讲解这两种类型中的分组聚合。spa
咱们来结合SQL Server 2012基础教程来看一个简单的例子code
USE TSQL2012
GO
SELECT custid, COUNT(shipcity) AS [shipcity_count]
FROM Sales.Orders
GROUP BY custid
上述查询计划比较简单咱们来解释下,首先经过默认主键建立的汇集索引来读取表中行数据,接着经过GROUP BY上指定的列custid来进行排序,咱们看到其排序操做具体信息就知道,以下。接着遍历全部custid,全部行被读取,开始一行行读取并计算其聚合表达式的值。重复处理直到完成为止。blog
对于经过流聚合对custid进行分组的示意图大概以下:排序
上述因为未对custid建立索引致使因此会经过Sort来进行排序,毫无疑问致使查询缓慢,这里咱们对custid建立非汇集索引再来看看状况教程
CREATE NONCLUSTERED INDEX idx_nc_custid ON Sales.Orders(custid)
此时查询将会充分利用索引,它会经过使用索引排序来进行聚合计算,因此就不会再利用Sort来排序致使性能低下,经过上述咱们知道,在进行Stream Aggregate以前事实上在指定的分组列上建立索引来预先排序会提升查询性能,而不须要再去利用Sort进行排序而耗费没必要要的时间。上述咱们已经说过在进行排序要么在GROUP BY上指定的列经过建立索引查找或者索引排序,若是GROUP BY中的列没有建立索引此时利用Sort来进行显示排序,以下显示指定ORDER BY custid来排序和没有指定的话结果依然都是使用Sort来排序,此时Stream Aggregate,其实这种说法不太准确,由于在SQL Server中有两种聚合方式,一种是Stream Aggregate,另一种则是Hash Match Aggregate。索引
USE TSQL2012
GO
SELECT custid, COUNT(shipcity) AS [shipcity_count]
FROM Sales.Orders
GROUP BY custid
ORDER BY custid
自从SQL Server 7以后就出现了Stream Aggregate和Hash Aggregate两种聚合方式,也就是说上述咱们稍做修改查询计划就变成了Hash Aggregate的形式。ip
USE TSQL2012 GO DBCC RULEOFF('GbAggToStrm'); GO SELECT custid, COUNT(shipcity) AS [shipcity_count] FROM Sales.Orders GROUP BY custid OPTION(RECOMPILE) GO DBCC RULEON('GbAggToStrm');
上述GbAggToStrm是什么鬼,其实若是查询计划中走的Stream Aggregate操做的话,也就说它走的是GbAggToStrm规则(GROUP BY Aggregate To Stream ),可是这里咱们关闭了查询计划本该走的Stream Aggregate操做即GbAggToStrm规则,因此此时它将只能走Hash Aggregate。因此到这里说明在排序时即便指定了ORDER BY操做有多是多余的,可是若是咱们不指定的话,要是咱们但愿返回的结果集是排序的,此时要是走的Hash Aggregate,结果返回的结果集将是无序的,致使咱们得不到想要的结果集,因此仍是但愿在排序时指定ORDER BY操做,这样可以避免没必要要的状况发生。
当查询中用到了DISTINCT关键字时,此时查询计划有可能走Stream Aggregate,也有可能走的是Hash Match Aggregate。因此在这里咱们分析下何时会用Hash Match Aggregate,何时又会用到Stream Aggregate。说到底DISTINCT关键字时用来去重的,在SQL Server中利用DISTINCT关键字来去重其查询计划走的方式分为两种,一种是在哈希表中创建惟一值,另一种则是将行进行排序分配到组中而后只返回组中的一个值便可。因此在SQL Server中使用Hash Match Aggregate来实现哈希表,使用Stream Aggregate或者DISTINCT Sort来对数据进行排序去重。
当咱们以下直接利用DISTINCT来查询时就是利用的DISTINCT Sort来排序去重。
USE TSQL2012 GO select DISTINCT custid FROM Sales.Orders
虽然很明确走的Sort,可是这是通过SQL查询引擎优化事后才有的,最原始的状况是先进行Sort接着进行Stream Aggregate,下面咱们关闭Sort的规则看看。
USE TSQL2012 GO DBCC RULEOFF('GbAggToSort') SELECT DISTINCT custid FROM Sales.Orders OPTION(RECOMPILE)
DBCC RULEON('GbAggToSort')
当未在列SomeColumn建立索引时咱们进行以下查询
USE TSQL2012
GO
SELECT DISTINCT SomeColumn
FROM dbo.BigTable
接下来咱们在列上建立索引
CREATE NONCLUSTERED INDEX idx_noncls_somecolumn ON dbo.BigTable(SomeColumn)
在建立索引时此时查询计划走的倒是Stream Aggregate,也就是说当利用DISTINCT关键字查询时且列已经进行了排序,此时查询计划走Stream Aggregate。那何时用Hash Match Aggregate呢,上述对列未建立索引时走的是Hash Match Aggregate由于数据量比较大此时还利用了并行计算,换句话说当对列未建立索引时且数据量很是大同时分组比较少时,查询计划更加更倾向于走Hash Match Aggregate,输入大量的数据经过Hash Match Aggregate结合并行计算效率也很是高,固然分组较少更好,此时不会太占用哈希表。接下来咱们限制查询结果集的条数。
USE TSQL2012 GO SELECT DISTINCT TOP 10 SomeColumn FROM dbo.BigTable
此时查询计划再也不是Hash Match Aggregate代替的是Hash Match(Flow Distinct)咱们看下msdn关于Flow Distinct的解释:Flow Distinct逻辑运算符用于经过扫描输入来删除重复项。虽然Distinct 运算符在生成任何输入前消耗全部的输入,但FlowDistinct 运算符在从输入得到行时返回每行(除非该行是一个重复项,如果这样则删除该行)
也就是说DISTINCT直接就过滤了重复行,而Flow Distict则得到每行时并返回每一行,这就是Flow Distinct,它的出现依赖于在查询计划中估计惟一值的数量,当咱们将TOP的数量设置为接近100万或者比100万还少一点时此时走的是Hash Match Aggregate。到此咱们关于Hash Match Aggregate和Stream Aggregate的分析算是结束了,咱们下个基本结论:
Hash Match Aggregate和Stream Aggregate分析结论:
(1)查询中有DISTINCT关键字时:当在查询列上建立索引时即列进行了排序时此时走Stream Aggregate,当数据量很是大时且未建立索引时此时通常走的是Hash Match Aggregate并结合并行计算,其他状况则是走的Distinct Sort。
(2)查询中没有DISTINCT关键字时,对于标量聚合和分组聚合走的是Stream Aggregate。
好了本节关于Hash Match Aggregate和Stream Aggregate的介绍就到此为止,基本算是了解,太复杂的也没去过多探讨,这是DBA的事情了,下一节咱们穿插讲讲关于计算列持久化系列文章,简短的内容,深刻的理解,咱们下节再会。