环境:

  Sql Server2012 SP3企业版,Windows Server2008 标准版

问题由来:

最近在做DB优化的时候,发现一个存储过程有非常严重的性能问题,

由于整个SP整体逻辑是一个多表关联的复杂的查询,整体结构比较复杂的,通过的分析和尝试,

最后发现问题出在其中一个大表的查询上实现方式上,

因为这个大表上的意外的执行方式,导致其他表无法被驱动,其他表也是表扫描的方式参与join

导致后面整个表之间join以及查询编译出来一系列极其低效的执行效果(不合理的执行计划)

这里单独将这个大表的查询提取出来作分析

下面就是我说的大表的这一步在默认情况下的执行情况,

这个表当时数据量是3000W条,符合查询条件的数据在50W左右(一个月的数据量),

因为考虑到结果集比较大,SSMS结果窗口加载数据耗时比较长

我将结果Insert到临时表的目的是减少SSMS加载数据的时间,更注重查询内部计算

不加强制索引提示下的执行情况(测试之前都DBCC dropcleanbuffer 清理缓存),完成整个查询耗时8S:

如下是sql查询执行信息

执行计划情况

可以看到它走了一个跟查询字段无关的普通索引的index scan的执行计划。

加上查询列上的强制索引提示的执行情况,完成这个查询耗时2S:

如果加一个查询列上的索引的查询提示,会发现性能上有一个比较明显的提升

当加上查询索引提示之后,2s中就完成了,比上面默认没有索引提示的方式提高了4倍

执行计划信息

这里就有一个问题,默认情况下为什么没有采用查询列所在的索引进行index seek的查找方式,而采用了另外一个索引进行index scan的方式?

如果没猜错的话,很可能有人跟我一样,是认为统计信息没有更新,索引碎片之类导致的

这个查询非常简单,到底是不是索引统计信息,或者索引碎片之类的引起的呢?

这个倒是好办,对这个表上的所有索引全部重建(rebuild),同时也会促使统计信息的更新。

然后继续测试,问题依旧!!!

基本上可以认为,外界条件没有额外干扰的情况下,Sql Server 始终没有选择一个执行速度较快的执行计划,

之所以说Sql Server没有选择执行速度较快的执行计划,而不是说最优的,是因为这个最优化执行计划是没办法直接去评判的,

如果你注意的话,会发现:

不加索引提示的时候:逻辑读是:589689,物理读是589723

加了索引提示的时候:逻辑读是:1992328,但是真正的物理读并不多,只有11229(Read Ahead Read)+2042(Physical Read)

          逻辑读的增加是在内存中作计算的时候产生的,查询过程有个较大的内存授予(Memory Grant)

          但是这并不影响后者执行时间更短,

          因为后者通过一个内存授予(Memory Grant),授予一个211M的物理内存用来暂存中间结果集来以更高效的方式来执行

          所以我前面说Sqlserver没有选择“执行速度较快”的执行计划,而不是说最优化的执行计划,

          因为后者执行更快,但是耗费了更多的服务器资源,前者执行较慢,但是没有耗费很多系统资源。

最优化的执行计划是一个很难用一棒子打死的方式去界定的,到底是以执行时间为评判,还是以资源消耗为评判?

我想sqlserver是以综合考量去评价的吧,出现这种情况,我只能推断:默认情况下,评估执行计划代价的时候,IO的系数在计算中的权重更大

如果服务器资源充足的情况下:

              肯定宁愿为其提供充足资源去让其更快地执行以相应应用程序的请求

如果服务器资源不够充足的情况下:

  这个SQl的运行需要这么多内存,

  可能就需要为了申请到(比第一种执行方式)足够多的内存而造成更长时间的等待(这里不细说,比如memory grants pending)

  此时,还不如让他慢慢执行,好歹还能跑出来结果。

这种究竟哪种方式好,哪种方式不好,很难有一个定论,一切都要根据具体情况来定,

数据库自身不太可能在任何情况下都作出最最明智的选择,这大概也就是各种关系数据库预留给用户一些查询提示的原因吧。

总结:

  以上粗浅地根据一个遇到的实例案例,通过认为改变默认情况下的执行计划来观察对比sql的执行效率,在我们对数据库进行性能调优时提供一种可参考的方法

  也能够帮助我们认识Sql Server在选择执行计划时候的一些特点,以帮助我们更加有效地使用Sql Server数据库。

后记:

另外,在优化这个SP的时候发现另外一个问题,

就是在默认情况下,进行全表扫描的时候,走的是一个普通的索引扫描(index scan),

原本这个表上有聚集索引,如果是全表扫描,完全可以走一个聚集索引扫描(clustered index scan),但是它走了普通索引上的索引扫描(index scan),

至于为什么走索引扫描,细心的话,大概会猜到,有人在这个表上建立了一个包含索引(include index),

就是在某个字段上建立一个索引把其他字段全部include进去,这样走索引扫描,也可以达到全表扫描这个查询的目的

通常是一些非专业人员,大概了解一些索引的原理,但是不够深入,会根据某些特定的情况,或者自己认为需要哪个列做索引,亦或是根据SSMS执行计划中的Missing index提示,

不加分析,随意、武断地去建立索引,

这样会导致表上的索引的占用空间,比整个表的数据空间还要大,甚至大几倍的情况都有,这会导致后记该表上进行增删改导致的一系列潜在的问题

当然不是说SSMS执行计划提示的缺失索引一无是处,但是建索引还是要客观,慎重,尤其是在操作频繁的大表上

索引也是一个极其有讲究的问题,这里就不展开论述了。

Sql Server优化之索引提示----我们为什么需要查询提示,Sql Server默认情况下优化策略选择的不足的更多相关文章

  1. spring 默认情况下事务是惟一的 同一个方法里面第一个sql开启后 在执行完 将事务传递给下一个sql

    spring 默认情况下事务是惟一的 同一个方法里面第一个sql开启后 在执行完 将事务传递给下一个sql

  2. 如何在不改SQL的情况下优化数据库

    主题简介 在数据库运维中我们会遇到各种各样的问题,这些问题的根源可能很明显,也可能被某种表象掩盖而使我们认不清.所以运维面临的两大问题就是,第一我们没有看清本质,第二应用不允许修改.那么我们如何解决这 ...

  3. 默认情况下安装的应用程序C盘后提示权限不足,当你开始介意。。。

    最近,不少用户抱怨的经销商.正在使用win 7我们的计算机系统上安装软件后,提示权限不够开放系统,无法启动软件. 在xp该系统是没有问题的.原因是,我们会选择在默认安装路径系统C-disk.和win ...

  4. VC6下 try catch 在release下的杯具(默认情况下,要加上throw语句catch才不会被优化掉)

    IDE:VC6 今天遇到一个小问题,把我郁闷了好久,××医生的VulEngine不时在wcsstr处发生crash,加了一番强大的参数检查后,再加上了强大的try catch,其实不是很喜欢用try和 ...

  5. ASP.NET Webform或者ASP.NET MVC站点部署到IIS下,默认情况下.json文件是不能被访问的,如果请求访问.json文件,则会出现找不到文件的404错误提示

    解决方法 <system.webServer> <staticContent> <remove fileExtension=".woff" /> ...

  6. python 11:range(起始索引,终止索引,步数)(默认情况下步数为1,生成从起始索引,每次增加(终止索引-起始索引)/步数,到终止索引前的数字串)

    squares = [] for value in range(1,11): #第三参数默认为1,生成从1开始,每次增加1步数,到11前的10为止的数字串 square = value ** 2 sq ...

  7. 关于MySQL中查询大数据量的情况下分页limit的性能优化

    https://blog.csdn.net/weixin_37848710/article/details/80772725

  8. SQL Server通过整理索引碎片和重建索引提高速度

    本文章转载:http://database.51cto.com/art/201108/282408.htm SQL Server数据库中,当索引碎片太多时,就会拖慢数据库查询的速度.这时我们可以通过整 ...

  9. SQL Azure (18) 使用External Table实现垮库查询

    <Windows Azure Platform 系列文章目录> 问题 1.我们在进行SQL Server开发的时候,经常会使用垮库查询.但是在默认情况下,使用Azure SQL Datab ...

随机推荐

  1. shell脚本调试

    转自:http://www.ibm.com/developerworks/cn/linux/l-cn-shell-debug/ 一. 前言 shell编程在unix/linux世界中使用得非常广泛,熟 ...

  2. Linux之脚本安装软件

      查看启动程序   ps aux    准备工作 1.保证yum源正常使用 2.关闭SELinux和防火墙   下载脚本文件包 解压缩 运行 ./centors.sh

  3. Mvc利用淘宝Kissy uploader实现图片批量上传附带瀑布流的照片墙

    前言 KISSY 是由阿里集团前端工程师们发起创建的一个开源 JS 框架.它具备模块化.高扩展性.组件齐全,接口一致.自主开发.适合多种应用场景等特性.本人在一次项目中层使用这个uploader组件. ...

  4. Guava - 并行编程Futures

    Guava为Java并行编程Future提供了很多有用扩展,其主要接口为ListenableFuture,并借助于Futures静态扩展. 继承至Future的ListenableFuture,允许我 ...

  5. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  6. leveldb源码学习系列

    楼主从2014年7月份开始学习<>,由于书籍比较抽象,为了加深思考,同时开始了Google leveldb的源码学习,主要是想学习leveldb的设计思想和Google的C++编程规范.目 ...

  7. kafka的一些认识

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com   近来无事研究了一下kafka,并且用golang连接kafka做了producer和consumer的简单测试 ...

  8. 人机大战之AlphaGo的硬件配置和算法研究

    AlphaGo的硬件配置 最近AlphaGo与李世石的比赛如火如荼,关于第四盘李世石神之一手不在我们的讨论范围之内.我们重点讨论下AlphaGo的硬件配置: AlphaGo有多个版本,其中最强的是分布 ...

  9. 程序员DNS知识指南

    本次内容比较hardcore,非科班出身可能会有理解障碍,可以考虑不用挣扎,直接放弃.毕竟普通驾驶员是不需要理解内燃机原理和曲轴如何做功的,所谓术业有专攻也,能看完的不是同行就是真爱~ 引 DNS对于 ...

  10. Springlake-01 介绍&功能&安装

    1. 简介与功能 1)Springlake 是一个企业内容平台SECP 2)是一个可配置的系统,80%内容可以配置 3)允许建立和配置垂直解决方案 4)敏捷和占用空间小,可伸缩 5)端到端的安全性与性 ...