在SQL Server里,你有没有想进行跨越多个列/纬度的聚集操作,不使用SSAS许可(SQL Server分析服务)。我不是说在生产里使用开发版,也不是说安装盗版SQL Server。

不可能的任务?未必,因为通过SQL Server里所谓的Grouping Sets就可以。在这篇文章里我会给你概括介绍下Grouping Sets,使用它们可以实现哪类查询,什么是它们的性能优势。

使用Grouping Sets的聚合

假设你有个订单表,你想进行跨多个分组的T-SQL聚集查询。在AdventureWorks2012数据库的Sales.SalesOrderHeader表的环境里,这些分组可以类似如下:

  • 在每列分组
  • GROUP BY SalesPersonID, YEAR(OrderDate)
  • GROUP BY CustomerID, YEAR(OrderDate)
  • GROUP BY CustomerID, SalesPersonID, YEAR(OrderDate)

当你想用传统T-SQL查询进行这些各自分组时,你需要多个语句,对各个记录集进行UNION ALL。我们来看这样的查询:

 1 SELECT * FROM
 2 (
 3     -- 1st Grouping Set
 4     SELECT
 5         NULL AS 'CustomerID',
 6         NULL AS 'SalesPersonID',
 7         NULL AS 'OrderYear',
 8         SUM(TotalDue) AS 'TotalDue'
 9     FROM Sales.SalesOrderHeader
10     WHERE SalesPersonID IS NOT NULL
11
12     UNION ALL
13
14     -- 2nd Grouping Set
15     SELECT
16         NULL AS 'CustomerID',
17         SalesPersonID,
18         YEAR(OrderDate) AS 'OrderYear',
19         SUM(TotalDue) AS 'TotalDue'
20     FROM Sales.SalesOrderHeader
21     WHERE SalesPersonID IS NOT NULL
22     GROUP BY SalesPersonID, YEAR(OrderDate)
23
24     UNION ALL
25
26     -- 3rd Grouping Set
27     SELECT
28         CustomerID,
29         NULL AS 'SalesPersonID',
30         YEAR(OrderDate) AS 'OrderYear',
31         SUM(TotalDue) AS 'TotalDue'
32     FROM Sales.SalesOrderHeader
33     WHERE SalesPersonID IS NOT NULL
34     GROUP BY CustomerID, YEAR(OrderDate)
35
36     UNION ALL
37
38     -- 4th Grouping Set
39     SELECT
40         CustomerID,
41         SalesPersonID,
42         YEAR(OrderDate) AS 'OrderYear',
43         SUM(TotalDue) AS 'TotalDue'
44     FROM Sales.SalesOrderHeader
45     WHERE SalesPersonID IS NOT NULL
46     GROUP BY CustomerID, SalesPersonID, YEAR(OrderDate)
47 ) AS t
48 ORDER BY CustomerID, SalesPersonID, OrderYear
49 GO

用这个T-SQL语句方法有多个缺点:

  • T-SQL语句本身很庞大,因为每个单独分组都是一个不同查询。
  • 每查询1次,Sales.SalesOrderHeader表需要访问4次。
  • 每查询1次,你在执行计划里会看到SQL Server进行了4次的索引查找(非聚集)(Index Seek (NonClustered) )

如果你使用自SQL Server 2008以后引入的grouping sets功能,就可以大大简化你需要的T-SQL代码。下面代码展示你同样的查询,但这次用grouping sets实现。

 1 SELECT
 2     CustomerID,
 3     SalesPersonID,
 4     YEAR(OrderDate) AS 'OrderYear',
 5     SUM(TotalDue) AS 'TotalDue'
 6 FROM Sales.SalesOrderHeader
 7 WHERE SalesPersonID IS NOT NULL
 8 GROUP BY GROUPING SETS
 9 (
10     -- Our 4 different grouping sets
11     (CustomerID, SalesPersonID, YEAR(OrderDate)),
12     (CustomerID, YEAR(OrderDate)),
13     (SalesPersonID, YEAR(OrderDate)),
14     ()
15 )
16 GO

从代码本身可以看到,你只在GROUP BY GROUPING SETS子句里指定需要的分组集——其它的一切都由SQL Server搞定。指定的空括号是所谓的Empty Grouping Set,是跨整个表的聚集。当你看STATISTICS IO输出时,你会发现Sales.SalesOrderHeader只被访问了1次!这是和刚才手工实现的巨大区别。

在执行计划里,SQL Server使用了Table Spool运算符,它把获得的数据临时存储在TempDb里。来自临时表里创建的Worktable的数据在执行计划的第2个分支被使用。因此对来自表的每个分组数据没有重新扫描,这就给整个执行计划的带来了更好的性能。

我们再来看下执行计划,你会发现查询计划包含了3个Stream Aggregate运算符(红色,蓝色,绿色高亮显示)。这3个运算符计算各个分组集:

  • 蓝色高亮的运算符计算CustomerID, SalesPersonID, YEAR(OrderDate的分组集。
  • 红色高亮的运算符计算SalesPersonID, YEAR(OrderDate)的分组集。另外也计算每1列的分组集。
  • 绿色高亮的运算符计算CustomerID, YEAR(OrderDate)的分组集。

2个连续的Stream Aggregate运算符的背后想法是计算所谓的Super Aggregates——聚集的聚集。

小结

在今天的文章里我给你介绍了grouping sets,在SQL Server 2008后引入的增强T-SQL。如你所见grouping sets有2个大优点:简化你的代码,只访问一次数据提高查询性能。

我希望现在你已经能够很好理解grouping sets,如果你能在你的数据库里使用这个功能可以在此留言,非常感谢!

感谢关注!

参考文章:

https://www.sqlpassion.at/archive/2014/09/15/the-power-of-grouping-sets-in-sql-server/

SQL Server里Grouping Sets的威力相关推荐

  1. SQL Server里PIVOT运算符的”红颜祸水“

    概述 SQL Server里PIVOT运算符背后的基本思想是在T-SQL查询期间,你可以旋转行为列.运算符本身是SQL Server 2005后引入的,主要用在基于建立在实体属性值模型(Entity ...

  2. SQL Server里的INTERSECT

    在今天的文章里,我想讨论下SQL Server里的INTERSECT设置操作.INTERSECT设置操作彼此交叉2个记录集,返回2个集里列值一样的记录.下图演示了这个概念. INTERSECT与INN ...

  3. 在SQL Server里如何进行页级别的恢复

    在今天的文章里我想谈下每个DBA应该知道的一个重要话题:在SQL Server里如何进行页级别还原操作.假设在SQL Server里你有一个损坏的页,你要从最近的数据库备份只还原有问题的页,而不是还原 ...

  4. SQL Server里的 ISNULL 与 Oracle 中的 NULLIF

    SQL Server里的 ISNULL 与 Oracle 中的 NULLIF不同: SQL Server 中有两个参数,语法:     ISNULL(check_expression, replace ...

  5. SQL Server里一些未公开的扩展存储过程

    SQL Server里一些未公开的扩展存储过程 [转帖] 博客天地 www.inbaidu.com SQL Server里一些未公开的扩展存储过程 扩展存储过程(xp)是直接运行在SQL Server ...

  6. 在SQL Server里为什么我们需要更新锁

    今天我想讲解一个特别的问题,在我每次讲解SQL Server里的锁和阻塞(Locking & Blocking)都会碰到的问题:在SQL Server里,为什么我们需要更新锁?在我们讲解具体需 ...

  7. SQL Server里的日期格式化

    1)SQL Server 里实现日期格式化需要到 convert()函数: CONVERT() 函数是把日期转换为新数据类型的通用函数,可以用不同的格式显示日期/时间数据. 语法:CONVERT(da ...

  8. 深入理解 SQL 中的 Grouping Sets 语句

    前言 SQL 中 Group By 语句大家都很熟悉,根据指定的规则对数据进行分组,常常和聚合函数一起使用. 比如,考虑有表 dealer,表中数据如下: id (Int) city (String) ...

  9. SQL Server里那些我们应该知道的系统存储过程

    SQL Server常见系统存储过程 1 sp_who 功能及说明: 当前数据库实例的用户.会话.进程信息. 参数主要包括用户(@loginame='xxxx').会话状态(仅活动的即ACTIVE). ...

最新文章

  1. 资料分享:送你一本《BigONE Developer API V2》电子书!
  2. 微信快速开发框架(六)-- 微信快速开发框架(WXPP QuickFramework)V2.0版本上线--源码已更新至github...
  3. js 正则表达式奇偶字符串替换_Python中的正则表达式及其常用匹配函数用法简介...
  4. method-dispatch/
  5. linux c嵌入汇编语言,Linux 下的C和Intel 汇编语言混用
  6. 同一页面引入多个JS文件的编码问题
  7. web加载本地html,WKWebview加载本地html问题汇总
  8. 在桌面应用中使用JAVA DB[组图]
  9. C++之继承探究(十):抽象基类与纯虚函数
  10. 画一个圆角多边形_用SolidWorks一个扫描画出这个多边形瓶子
  11. bzoj 1433: [ZJOI2009]假期的宿舍
  12. 开始菜单单如何打开计算机程序,什么是开始菜单
  13. DSP应用技术(第一章)
  14. 神经网络中经常使用的激活函数--sigmoid函数
  15. 【亲测】超级外链SEO工具源码,可发9600条优质外链
  16. 计算机系系徽设计说明,系徽设计大赛策划书
  17. 景区环境监测系统监测天气与客流量
  18. EleutherAI GPT-Neo: 穷人的希望
  19. iptables 2: 规则的查看、添加、删除、修改
  20. java8 list max_Java 在List 上使用.max()和.stream()

热门文章

  1. 学习笔记99—word 如何增加底纹
  2. 预处理器Less和Sass
  3. 反射 reflect
  4. [sh]top添加到crontab不生效问题解决
  5. android加载html
  6. Android-ImageLoader的最基础的操作
  7. Hybrid App开发者一定不要错过的框架和工具
  8. html 商品展示框
  9. Linux卸载蓝牙模块,Linux 下调试低功耗蓝牙的笔记
  10. 8. An Introduction to MCMC for Machine Learning (5)