SQL Server信息偏差影响表联结方式统计
SQL Server统计信息偏差影响表联结方式案例浅析
我们知道数据库中的统计信息的准确性是非常重要的。它会影响执行计划。一直想写一篇关于统计信息影响执行计划的相关博客,但是都卡在如何构造一个合适的例子上,所以一直拖着没有写。巧合,最近在生产环境中遇到这么一个案例,下面对案例中的相关信息做了脱敏处理,有些中间步骤也省略了,只关注核心部分SQL。如下所示,同事反馈一个SQL语句执行很慢。
UPDATE b
SET b.[Status] = '已扫描,未签收' ,
b.[Time] = pr.CreatedDate
FROM #Batch b
JOIN WDPM.PdaRecords pr WITH ( NOLOCK ) ON b.Batch_No = pr.OrderNo
AND pr.FunctionName = '[WDPM].[usp_SaveOutOrder]'
WHERE b.[Status] = '已打单,未扫描'
AND pr.CreatedDate > b.[Time];
如下截图所示,这个SQL语句基本上耗时271秒。一个临时表与一个表做嵌套循环连接(Nested Loops)。 因为表WDPM.PdaRecords只有一个聚集索引,所以执行计划中,这个表走聚集索引扫描。
注意:这里表WDPM.PdaRecords本身缺少合适的索引,只有一个聚集索引。后面展开讲述这个问题.这里先围绕统计信息的准确性对执行计划的影响来展开讲述。
物理表WDPM.PdaRecords的数据量为2505369(当然这个是一直在变化的。这个数值仅仅是实验前的检测记录,一直有会话对其进行DML操作,所以数据会变化,所以这里没有列出统计信息截图)。
我们看到Table Scan部分,预估行数(Estimated Number of Rows)为1, 实际行数为150。 这个偏差已经比较大了。
对于物理表WDPM.PdaRecords而言,基数估计的预估行数(Estimated Number of Rows)为921771, 但是由于嵌套循环连接,所以累加起来的实际行数(Actual Number of Rows)为: 921771*150 =138265650 。
我们知道嵌套循环(Nested Loops)算法的时间复杂度为N*M, N的预估值从1变成了150 ,这里面的偏差就大了(因为每次聚集索引扫描的开销也很大)。所以导致优化器在表的物理连接方式上选择了嵌套循环(Nested Loops), 因为预估的代价是很小的。但是实际因为统计信息的误差,导致这个代价放大了150倍。那么如果我们更新临时表的统计信息呢?然后执行这个SQL,会有什么变化呢?
如下所示,我们在执行SQL语句前,更新一下临时表的统计信息。发现优化器在获取了准确的统计信息后,在表的物理连接上选择了Hash Join方式。而且SQL语句耗时变成了1秒多。为什么呢? 因为优化器发现选择Nested Loops的代价远远高于 Hash Join。所以它在获取了准确的信息后,作出了最优选择。之前之所以生成了一个错误的执行计划,就是因为它得到的“信息”不准确,导致它作出了错误的抉择。这个就好比你获取了错误的信息,作出了错误的选择,购买了一只错误的股票,而巴菲特由于掌握了准确的行业信息,作出了正确的选择。 购买了几只购票都大涨了。
UPDATE STATISTICS #Batch WITH FULLSCAN;
UPDATE b
SET b.[Status] = '已扫描,未签收' ,
b.[Time] = pr.CreatedDate
FROM #Batch b
JOIN WDPM.PdaRecords pr WITH ( NOLOCK ) ON b.Batch_No = pr.OrderNo
AND pr.FunctionName = '[WDPM].[usp_SaveOutOrder]'
WHERE b.[Status] = '已打单,未扫描'
AND pr.CreatedDate > b.[Time];
当然,了解到这里,还远远没有结束。我们发现表WDPM.PdaRecords 只有一个聚集索引,而且聚集索引位于Iden自增字段上,从另外一个角度来看,这个表其实是缺少合适的索引的。那么我们可以创建一个索引。
CREATE INDEX IX_PdaRecords_N1 ON wdpm.PdaRecords(OrderNo,FunctionName)
创建索引后,即使不更新临时表#Batch的统计信息,我们发现执行计划也会走嵌套循环(Nested Loops),而不会走Hash Join了。这个又是什么原因呢?
此处截图,是第二次执行SQL,临时表的数据变化了(生成临时表的数据的SQL有好几个,每次执行获取的数据都会有部分变化)
因为有了合适的索引,趋近准确的统计信息,以及谓词下推(predicate push down),基数(Cardinality)的预估行数(Esitmted Row Size)为35.0545 与实际行数(Actual Number of Rows)为666, 这样即使循环次数为140. 总的访问记录数为140*666=93240 , 这个是远远小于之前错误执行计划的138265650 。所以即使临时表的#Batch的统计信息有误,但是优化器还是生成了一个不错的执行计划。这样SQL的执行时间也就缩短到了1秒内.
这个案例仅仅是为了展示:统计信息的准确与否,会导致优化器生成的执行计划选择不同的表连接方式, 例如从嵌套循环(Nested Loops)变成Hash Join。 仅仅是为了说明统计信息准确的重要性。
SQL Server信息偏差影响表联结方式统计的更多相关文章
- SQL Server统计信息偏差影响表联结方式案例浅析
我们知道数据库中的统计信息的准确性是非常重要的.它会影响执行计划.一直想写一篇关于统计信息影响执行计划的相关博客,但是都卡在如何构造一个合适的例子上,所以一直拖着没有写.巧合,最近在生产环境中遇到 ...
- Sql server中如何将表A和表B的数据合并(乘积方式)
sql server中如何将表A 和表B的数据合并成乘积方式,也就是说表A有2条数据,表B有3条数据,乘积后有6条数据, 这就要用到sql中的笛卡尔积方式了 1.什么是笛卡尔积 笛卡尔积在SQL中的实 ...
- SQL Server中的三种Join方式
1.测试数据准备 参考:Sql Server中的表访问方式Table Scan, Index Scan, Index Seek 这篇博客中的实验数据准备.这两篇博客使用了相同的实验数据. 2.SQ ...
- SQL Server中数据库文件的存放方式,文件和文件组
原文地址:http://www.cnblogs.com/CareySon/archive/2011/12/26/2301597.html SQL Server中数据库文件的存放方式,文件和文件组 ...
- MS SQL SERVER 中的系统表
MS SQL SERVER 中的系统表 序号 名称 说明 备注 1 syscolumns 每个表和视图中的每列在表中占一行,存储过程中的每个参数在表中也占一行. 2 syscomments 包含每 ...
- Sql Server系列:数据表操作
表是用来存储数据和操作数据的逻辑结构,用来组织和存储数据,关系数据库中的所有数据都表现为表的形式,数据表由行和列组成.SQL Server中的数据表分为临时表和永久表,临时表存储在tempdb系统数据 ...
- SQL Server跨库复制表数据错误的解决办法
SQL Server跨库复制表数据的解决办法 跨库复制表数据,有很多种方法,最常见的是写程序来批量导入数据了,但是这种方法并不是最优方法,今天就用到了一个很犀利的方法,可以完美在 Sql Serv ...
- SQL Server 执行计划中的扫描方式举例说明
SQL Server 执行计划中的扫描方式举例说明 原文地址:http://www.cnblogs.com/zihunqingxin/p/3201155.html 1.执行计划使用方式 选中需要执行的 ...
- SQL Server 2014内存优化表的使用场景
SQL Server 2014内存优化表的使用场景 最近一个朋友找到走起君,咨询走起君内存优化表如何做高可用的问题 大家知道,内存优化表是从SQL Server 2014开始引入,可能大家对内存优化表 ...
随机推荐
- 将本地项目部署到github远程仓库
近期写了一些项目,想把项目代码保存并分享出来,所以就想到了github. 下面就为大家介绍部署过程: 安装git客户端,请大家百度自行下载,这里就不做介绍了. 注册github账号,这个很简单,这里就 ...
- 蓝图Blueprint
---恢复内容开始--- 蓝图: flask模块化处理操作和URL的方式 作用: 将不同的功能模块化,实现模块化应用 构建大型应用 优化项目结构 使用步骤 创建蓝图对象 对蓝图对象进行操作(注册路由; ...
- 关于FFmpeg工具的使用总结
FFmpeg官网:http://ffmpeg.org/ 安装ffmpeg: http://www.cnblogs.com/freeweb/p/6897907.html 主要参数: -i 设定输入流 - ...
- 分享:五个非常有用的WP插件
一全老师(www.yiquanseo.com)认为非常有用的几款WP插件,用WordPress做站的可以看下,估计你很可能用得到! 第一款WooCommerce Page Builder: 这款插件是 ...
- Altium 添加altera 或xilinx 芯片库的方法
从altera或xilinx官网下载库,在library添加即可
- C++11 相关教程
C++11 中文wiki: https://zh.wikipedia.org/zh-cn/C%2B%2B11 C++11 新特性介绍: https://www.kancloud.cn/wangshub ...
- 【亲测】Asp.net Mvc5 + EF6 code first 方式连接MySQL总结
本文原文地址为:https://www.cnblogs.com/summit7ca/p/5423637.html 原文测试环境为windows 8.1+Vs2013+MySql5.7.12 本人在wi ...
- L343 中译英
爱显摆的人遇事总喜欢标新立异.Showoffs never miss an opportunity to draw attention to themselves by some outrageous ...
- volatile--领域分界线?
volatile是一个类型修饰符(type specifier),就像大家更熟悉的const一样,它是被设计用来修饰被不同线程访问和修改的变量.volatile的作用是作为指令关键字,确保本条指令不会 ...
- Sql Prompt---Unable to connect to the Redgate Client Service
今天在使用SQLPrompt时,突然发现所有的提示都不能用了,在百度上搜索无果,刚刚在Google搜索,果然找到了自己想要的答案,今天把搜索的结果发布在此,希望能够帮助到有需要的朋友. 客户端服务停止 ...