设为首页 收藏本站
查看: 3132|回复: 0

[经验分享] SQL Server-聚焦查询计划Stream Aggregate VS Hash Match Aggregate(二十)

[复制链接]

尚未签到

发表于 2017-7-13 13:03:54 | 显示全部楼层 |阅读模式
前言
  之前系列中在查询计划中一直出现Stream Aggregate,当时也只是做了基本了解,对于查询计划中出现的操作,我们都需要去详细研究下,只有这样才能对查询计划执行的每一步操作都了如指掌,所以才有了本文的出现,简短的内容,深入的理解,Always to review the basics。

Stream Aggregate
  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
DSC0000.png

  下面我们再来分组聚合的例子



USE TSQL2012
GO
SELECT custid
FROM Sales.Orders
GROUP BY custid
DSC0001.png

  上述就是Stream Aggregate两种类型的例子,关于标量聚合比较简单直接利用聚合函数就行,下面我们主要详细讲解这两种类型中的分组聚合。

分组聚合
  我们来结合SQL Server 2012基础教程来看一个简单的例子



USE TSQL2012
GO
SELECT custid, COUNT(shipcity) AS [shipcity_count]
FROM Sales.Orders
GROUP BY custid
DSC0002.png

  上述查询计划比较简单我们来解释下,首先通过默认主键创建的聚集索引来读取表中行数据,接着通过GROUP BY上指定的列custid来进行排序,我们看到其排序操作具体信息就知道,如下。接着遍历所有custid,所有行被读取,开始一行行读取并计算其聚合表达式的值。重复处理直到完成为止。
DSC0003.png

  对于通过流聚合对custid进行分组的示意图大概如下:
DSC0004.png

  上述由于未对custid创建索引导致所以会通过Sort来进行排序,毫无疑问导致查询缓慢,这里我们对custid创建非聚集索引再来看看情况



CREATE NONCLUSTERED INDEX idx_nc_custid ON Sales.Orders(custid)
DSC0005.png

  此时查询将会充分利用索引,它会通过使用索引排序来进行聚合计算,所以就不会再利用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的形式。



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在Hash Match Aggregate和Stream Aggregate和DISTINCT Sort中的使用
  当查询中用到了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
  当我们如下直接利用DISTINCT来查询时就是利用的DISTINCT Sort来排序去重。



USE TSQL2012
GO
select DISTINCT custid
FROM Sales.Orders
DSC0006.png

  虽然很明确走的Sort,但是这是经过SQL查询引擎优化过后才有的,最原始的情况是先进行Sort接着进行Stream Aggregate,下面我们关闭Sort的规则看看。



USE TSQL2012
GO
DBCC RULEOFF('GbAggToSort')
SELECT DISTINCT custid
FROM Sales.Orders
OPTION(RECOMPILE)

DBCC RULEON('GbAggToSort')
DSC0007.png


使用DISTINCT关键字走Hash Match Aggregate
  当未在列SomeColumn创建索引时我们进行如下查询



USE TSQL2012
GO
SELECT DISTINCT SomeColumn
FROM dbo.BigTable
DSC0008.png

  接下来我们在列上创建索引



CREATE NONCLUSTERED INDEX idx_noncls_somecolumn ON dbo.BigTable(SomeColumn)
DSC0009.png

  在创建索引时此时查询计划走的却是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
DSC00010.png

  此时查询计划不再是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的事情了,下一节我们穿插讲讲关于计算列持久化系列文章,简短的内容,深入的理解,我们下节再会。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-393430-1-1.html 上篇帖子: Sql Server海量数据插入 下篇帖子: SQL Server 分页方法汇总
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表