相关列的基数计算

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

在今天的文章里我想谈下基数计算里的一个特定问题:在查询谓语里相关列的基数计算。首先我们看下在SQL Server 7.0起的操作方法,最后我们详细看下SQL Server 2014里,在查询期间,处理相关列基数计算的全新实现方式。

什么是相关列(Correlated Columns)

在我们进入问题细节前,我们必须要澄清什么是相关列。当我们看SQL Server使用的查询优化器时,查询优化器是基于4个核心假设:

  • 独立性(Independence)
  • 一致性(Uniformity)
  • 密封度(Containment)
  • 夹杂物(Inclusion)

我不想细谈每个假设,因为它们在其它的白皮书里解释得非常清楚。在文章末尾的小结部分你会找到白皮书的链接。今天我们要聚焦的是第1个假设——独立性(Independence)。独立性意味这在查询谓语(WHERE子句)里用到的列是独立的,当各自查询时,会返回不同的记录。它们彼此间互不影响。遗憾的是这个假设并不都正确。我们来看一个具体的例子,这里违反了假设。假设下列2个查询: 

复制代码
1 SELECT * FROM Sales.SalesOrderHeader
2 WHERE SalesOrderID > 74000 AND SalesOrderID < 75000
3 GO
4 
5 SELECT * FROM Sales.SalesOrderHeader
6 WHERE OrderDate >= '20080626' AND OrderDate <= '20080724'
7 GO
复制代码

 第1个查询返回999条记录,第2个查询返回1125条记录。但符合这2个查询条件的记录是912条,这就是说这2列之间是有关联的。但是查询优化器并没有意识到这点。 

SQL Server 7.0-2012的基数计算

现在我们来看下SQL Server 7.0-2012是如何处理这个相关列的。在具体的执行计划里,第1个查询里,查询优化器估计行数是999.936,第2个查询里,查询优化器估计行数是1125。

用那些信息就与基数计算我们的表(这里表总记录数是31465),我们可以计算出查询谓语所谓的选择度(Selectivity)。选择度是0到1的数字。选择度越小,从查询返回的记录越少(0表示0%的记录返回,1表示100%的记录返回)。我们可以通过估计行数除以表存储的总记录数来计算查询谓语的选择度。因此第1个查询谓语的选择度是0.03177931034482758620689655172414(999/31465),第2个查询谓语的选择度是0.03575401239472429683775623708883(1125/31465)。现在我们来看下如果我们使用AND运算符组合2个查询谓语会发生什么:

1 SELECT * FROM Sales.SalesOrderHeader
2 WHERE SalesOrderID > 74000 AND SalesOrderID < 75000
3 AND OrderDate >= '20080626' AND OrderDate <= '20080724'
4 GO

当你查看执行计划时,查询优化器在聚集索引查找(聚集的)(Clustered Index Seek (Clustered)  )运算符上的估计行数是35.7517。

实际执行返回是如刚才提到的912行。这个差异太大了。查询优化器只是把2个查询谓语的选择度值相乘得出最后的估计行数。SQL Server假设2个查询谓语返回不同的行——假设这2列是彼此独立的:

0.03177931034482758620689655172414 * 0.03575401239472429683775623708883 * 31465 = 35.7517241379310344827586206896586

当然,事实是完全不一样的,因为在2个查询谓语间有巨大的关联。因此你会看到估计行数和行数之间有绝大的差异。在查询里使用更多的AND组合各个查询谓语,差异就会更大。当最后估计将至1行时,查询优化器总会估计至少1行——从不估计0行。

SQL Server 2014的基数计算

你可能已经听说了,SQL Server 2014包含了一个新的基数计算。一旦你的数据库是在120的兼容模式,新的基数计算就会用到。注意,当你从老版本的SQL Server还原或附加数据库时——这里的兼容性会变成老的!如果你想步改变兼容模式使用新的基数计算,你也可以使用新的2312跟踪标记。现在让我们对查询启用2312跟踪标记来让刚才的2个查询谓语使用新的基数计算。 

复制代码
1 SELECT * FROM Sales.SalesOrderHeader
2 WHERE SalesOrderID > 74000 AND SalesOrderID < 75000
3 AND OrderDate >= '20080626' AND OrderDate <= '20080724'
4 OPTION (RECOMPILE, QUERYTRACEON  2312)
5 GO
复制代码

 当你查看执行计划时,你会看到基数计算已经变了。

现在新的基数计算估计行数是188898.比刚才的老的基数计算的35.75行大很多。但到查询实际返回的912行还是有个大的缺口。不过现在新的基数估计用的是什么公式呢?新的基数计算使用所谓的指数退避算法(Exponential Back-off algorithm)。查询优化器取走这4个查询谓语,根据它们的选择度排序。所有的选择度再次相互相乘,但这里不同的是每个子过程值通过更大的平方根来软化。我们来看下公式来来理解这个行为:

c0 * (c1 ^ 1/2) * (c2 ^1/4) * (c3 ^ 1/8)

我们来看下具体的例子,通过下列计算就可以获得最终的基数:

0.03177931034482758620689655172414 * SQRT(0.03575401239472429683775623708883) * 31465 = 189.075212620762

比起188.898的估计行数我们的计算还有小差异,因为在SQL Server提供给执行计划里的估计行数是999.936行。使用指数退避算法,查询优化器可以确保做出更好的估计收紧估计行数和实际行数的洞,如果接受的查询参数之间有关联的话。

 小结

在这篇文章里我们谈了关系数据库里基数计算期间的特定问题:作为查询谓语使用的关联列如何使用基数估计。在SQL Server 2014之前,查询优化器使用不同选择值相乘,非常平稳的方法。这会导致巨大的低估,如果执行计划里前一个运算符(例如Sort或Hash运算符)基于这些估计,它会引起麻烦。



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

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
相关文章
|
4月前
【每日一题Day227】LC2465不同的平均值数目 | 排序 + 哈希表
【每日一题Day227】LC2465不同的平均值数目 | 排序 + 哈希表
17 0
|
6月前
35EasyUI 数据网格- 列运算
35EasyUI 数据网格- 列运算
16 0
给定一个数值,计算最合适的行列数量的代码
给定一个数值,计算最合适的行列数量的代码
71 0
|
存储 索引
599. 两个列表的最小索引总和 : 哈希表模拟题
599. 两个列表的最小索引总和 : 哈希表模拟题
|
Python
按照A列进行分组并计算出B列每个分组的平均值,然后对B列内的每个元素减去分组平均值
按照A列进行分组并计算出B列每个分组的平均值,然后对B列内的每个元素减去分组平均值
179 0
按照A列进行分组并计算出B列每个分组的平均值,然后对B列内的每个元素减去分组平均值
|
关系型数据库 MySQL
mysql查询最接近的值,查询最接近某一值的数据
mysql查询最接近的值,查询最接近某一值的数据
509 0