SQL Server-聚焦查询计划Stream Aggregate VS Hash Match Aggregate(二十)

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
简介:

前言

之前系列中在查询计划中一直出现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

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

复制代码
USE TSQL2012
GO

SELECT custid
FROM Sales.Orders
GROUP BY custid
复制代码

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

分组聚合

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

复制代码
USE TSQL2012
GO

SELECT custid, COUNT(shipcity) AS [shipcity_count]
FROM Sales.Orders
GROUP BY custid
复制代码

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

对于通过流聚合对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的形式。

复制代码
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

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

复制代码
USE TSQL2012
GO

DBCC RULEOFF('GbAggToSort')
SELECT DISTINCT custid
FROM Sales.Orders
OPTION(RECOMPILE)
DBCC RULEON(
'GbAggToSort')
复制代码

使用DISTINCT关键字走Hash Match Aggregate

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




本文转自Jeffcky博客园博客,原文链接:http://www.cnblogs.com/CreateMyself/p/6170565.html,如需转载请自行联系原作者

目录
相关文章
|
2月前
|
SQL 监控 关系型数据库
一键开启百倍加速!RDS DuckDB 黑科技让SQL查询速度最高提升200倍
RDS MySQL DuckDB分析实例结合事务处理与实时分析能力,显著提升SQL查询性能,最高可达200倍,兼容MySQL语法,无需额外学习成本。
|
2月前
|
SQL 存储 关系型数据库
MySQL体系结构详解:一条SQL查询的旅程
本文深入解析MySQL内部架构,从SQL查询的执行流程到性能优化技巧,涵盖连接建立、查询处理、执行阶段及存储引擎工作机制,帮助开发者理解MySQL运行原理并提升数据库性能。
|
2月前
|
SQL 监控 关系型数据库
SQL优化技巧:让MySQL查询快人一步
本文深入解析了MySQL查询优化的核心技巧,涵盖索引设计、查询重写、分页优化、批量操作、数据类型优化及性能监控等方面,帮助开发者显著提升数据库性能,解决慢查询问题,适用于高并发与大数据场景。
|
6月前
|
SQL 数据挖掘 数据库
第三篇:高级 SQL 查询与多表操作
本文深入讲解高级SQL查询技巧,涵盖多表JOIN操作、聚合函数、分组查询、子查询及视图索引等内容。适合已掌握基础SQL的学习者,通过实例解析INNER/LEFT/RIGHT/FULL JOIN用法,以及COUNT/SUM/AVG等聚合函数的应用。同时探讨复杂WHERE条件、子查询嵌套,并介绍视图简化查询与索引优化性能的方法。最后提供实践建议与学习资源,助你提升SQL技能以应对实际数据处理需求。
415 1
|
1月前
|
SQL 关系型数据库 MySQL
(SQL)SQL语言中的查询语句整理
查询语句在sql中占了挺大一部分篇幅,因为在数据库中使用查询语句的次数远多于更新与删除命令。而查询语句比起其他语句要更加的复杂,可因为sql是数据库不可或缺的一部分,所以即使不懂,也必须得弄懂,以上。
158 0
|
3月前
|
SQL XML Java
通过MyBatis的XML配置实现灵活的动态SQL查询
总结而言,通过MyBatis的XML配置实现灵活的动态SQL查询,可以让开发者以声明式的方式构建SQL语句,既保证了SQL操作的灵活性,又简化了代码的复杂度。这种方式可以显著提高数据库操作的效率和代码的可维护性。
235 18
|
3月前
|
SQL 人工智能 数据库
【三桥君】如何正确使用SQL查询语句:避免常见错误?
三桥君解析了SQL查询中的常见错误和正确用法。AI产品专家三桥君通过三个典型案例:1)属性重复比较错误,应使用IN而非AND;2)WHERE子句中非法使用聚合函数的错误,应改用HAVING;3)正确的分组查询示例。三桥君还介绍了学生、课程和选课三个关系模式,并分析了SQL查询中的属性比较、聚合函数使用和分组查询等关键概念。最后通过实战练习帮助读者巩固知识,强调掌握这些技巧对提升数据库查询效率的重要性。
119 0
|
5月前
|
SQL 关系型数据库 PostgreSQL
CTE vs 子查询:深入拆解PostgreSQL复杂SQL的隐藏性能差异
本文深入探讨了PostgreSQL中CTE(公共表表达式)与子查询的选择对SQL性能的影响。通过分析两者底层机制,揭示CTE的物化特性及子查询的优化融合优势,并结合多场景案例对比执行效率。最终给出决策指南,帮助开发者根据数据量、引用次数和复杂度选择最优方案,同时提供高级优化技巧和版本演进建议,助力SQL性能调优。
480 1
|
4月前
|
SQL
SQL中如何删除指定查询出来的数据
SQL中如何删除指定查询出来的数据
|
6月前
|
SQL 关系型数据库 MySQL
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路