《T-SQL性能调优秘笈——基于SQL Server 2012 窗口函数》——1.2 使用窗口函数的解决方案简介

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介:

本节书摘来自异步社区出版社《T-SQL性能调优秘笈——基于SQL Server 2012 窗口函数》一书中的第1章,第1.2节,作者: 【美】Itzik Ben-Gan,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.2 使用窗口函数的解决方案简介

T-SQL性能调优秘笈——基于SQL Server 2012 窗口函数
本书前4章描述了窗口函数及其优化,所选素材偏重技术说明,虽然我自己觉得很吸引人,但可以想见,有些人会觉得有点沉闷。通常来说,人们在阅读用窗口函数解决现实问题的内容时,会觉得比较有趣,本书将在最后一章满足大家。只有当我们看到能如何用窗口函数解决难题时,才会真正认识到它们的价值。所以,我在思考如何说服你在读到有趣的章节之前,能坚持读完这些枯燥的技术说明而不中途放弃。也许我可以展示一个窗口函数解决方案示例。

这里演示的查询包含:对一个在列中包含序列号的表进行查询,在现有值中找到连贯的区间。这个难题也就是所谓的数据岛问题。序列号可以是数值类型的、时间类型的(比较常见)或支持全排序的任意数据类型。序列号可以是唯一值,也可以是重复值。间隔可以是任何符合列类型(如,整型数1、整型数7、时间间隔为1天、时间间隔为2周等)的固定间隔。第5章会讲述间隔的各种变化。这里只举个简单的案例,让大家感受一下窗口函数是如何工作的——所以用数值序列,间隔为1,首先用下面的代码来生成样本数据:

image

在表T1中,可以看到col1的序列号并不连续。我们的任务是找到现有值的连续区间(也称为数据岛,)返回每个数据岛的开始值和结束值,我们希望得到的结果如下:

image

如果我们好奇这类问题在现实中的使用场景,这里有很多实际例子。示例包括生成可用性报告,识别某种活动的持续时间(如,销售活动),找到满足一定要求的持续区间(如,股票高于或低于一定阈值的时间区间),识别车牌的使用范围等。当前示例的目的非常简单,我们可以专注在实现它的技术上。只须稍作调整,应用在简单案例上的技术就可以应用在更加复杂的案例上,所以请把它看成是一个基于集合的解决方案带来的挑战。首先请找出一个能解决问题的方案,然后对表填充大量的数据行(假设10 000 000行)然后再试试刚才的解决方案,看看它将如何进行。完成这些,我们再来看我的解决方案。

在展示使用窗口函数的方案之前,我先展示其中一个用传统语言结构实现的解决方案。特别地,我会展示使用子查询的解决方案。为了解释第一种解决方案的策略,先查看T1.col1序列的值,我增加了一个目前尚不存在的概念化的列,把它当做组标识符:

image

grp列尚未存在,从概念上来说,它的值唯一地标识一个数据岛。这就意味着,对同一个岛内的所有成员,它们的grp值相同,并与其他岛内的成员的grp值不同。如果我们能设法对这样的组标识符进行计算,我们就能把结果根据grp特性值进行分组,返回每组(岛)中最大和最小的col1值。传统语言结构中生成这个组标识符的方法是:针对col1的每个当前值,找到大于或等于当前值的最小的col1值,并且要求这个值后面没有值。

举例说明,按照上面的逻辑,试着找到相对于值2,col1的值大于或等于2的最小值,且要求其后面的值没有连续,答案是3。现在,针对3,做同样的查找,结果还是3,所以3是组标识符,数据岛开始于2,结束于3。对于开始于11,结束于13的数据岛,组成员的标识符都是13。从这里我们可以看到,一个数据岛内的所有成员的组标识符,实际上就是数据岛最后一个成员的值。

下面是实现这个概念的T-SQL代码。

image

代码执行后的输出结果如下:

image

下面的部分就相当直观了——根据上面的查询定义表表达式,在外部查询中,根据组标识符进行分组,返回每组的最大和最小的col值,如下。

image

在这个解决方案里,有两个主要问题。一、这里遵循的逻辑有点复杂。二、运行非常缓慢。我暂时不想开始讨论查询执行计划——后面的篇幅有很多这方面的讨论——在这儿可以告诉大家,针对表中的每一行,SQL Server都几乎执行了两次完整的数据扫描。现在可以想象对于10 000 000条记录组成的序列,尝试转化它对应的工作量会有多少了。需要处理的行的数量只有一个词形容——巨大。

另一个解决方案也是计算组标识符,不同之处是,使用窗口函数进行。解决方案的第一步是使用ROW_NUMBER函数基于col1排序计算行号。本书后面会提供ROW_NUMBER的细节。目前,只要知道它在分区中,按照给定的顺序,从1开始,逐一递增,产生唯一的整数就足够了。

牢记上面的知识,下面的查询按照col1排序,返回的col1的值和行号。

image

现在,我把注意力集中到两个序列上。一个(col1)是不连贯的,另一个(rownum)是连贯的。记住这一点,然后尝试发现在一个数据岛内,二者有什么独特的关系。在数据岛内,两个序列都以固定间隔在增长,因此,二者的差异是一个常数。在另一个岛内,col1的增量超过1,而rownum的增量还是1,所以差异在变大。换句话说,二者的差异是常数,不同数据岛内的数值不同。运行下面的查询来计算其差异。

image

我们可以看到,这个差异满足我们对组标识符的两个需求,因此,可以把它当做组标识符使用。其他内容都与之前的解决方案相同,即是说,把行按组标识符进行分组,返回每组中最小和最大的col1值,如下所示。

image

请观察一下,这样的解决方案多么清晰和简单。同时,在代码上加上注释,帮助那些第一次读代码的人更好地了解解决方案,也是个不错的主意。

这个解决方案还很高效。与前一解决方案相比,其所涉及的行的处理数量微不足道。它仅仅包含一个在col1上的排序索引扫描和一个持续递增计数器的迭代器。我测试过这条查询的性能,它在10 000 000条记录组成的序列上仅运行了10秒钟。前一解决方案的运行时间就要长得多。

希望关于使用窗口函数的解决方案的简介,能足以吸引你,让你看到它们包含的强大功能。现在,我们要返回继续学习窗口函数技术了,在书的后面部分,我们还有机会看到更多的示例。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
14天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
52 10
|
1月前
|
SQL 数据库 数据安全/隐私保护
Sql Server数据库Sa密码如何修改
Sql Server数据库Sa密码如何修改
|
24天前
|
SQL
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
17 0
|
14天前
|
SQL 算法 数据库
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
82 6
|
2天前
|
SQL 关系型数据库 MySQL
:“You have an error in your SQL syntax; check the manual that corresponds to your MySQL server versi
:“You have an error in your SQL syntax; check the manual that corresponds to your MySQL server versi
9 0
|
9天前
|
SQL 安全 网络安全
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
20 0
|
14天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
16天前
|
SQL 数据库 索引
SQL索引失效原因分析与解决方案
SQL索引失效原因分析与解决方案
22 0
|
18天前
|
SQL 数据安全/隐私保护
SQL Server 2016安装教程
SQL Server 2016安装教程
21 1
|
18天前
|
SQL 安全 Java
SQL server 2017安装教程
SQL server 2017安装教程
16 1