有个系统,昨天Support人员发布了相关升级脚本后,今天发现系统中有个功能不能正常使用了,直接报超时了(Timeout expired)的错误。定位到相关相关存储过程后,然后在优化分析的过程中,又遇到了执行计划COST “欺骗”我们的这种情况,其实在我这篇博客”SQL SERVER中用户定义标量函数(scalar user defined function)的性能问题“有提及这个问题,但是很多时候,我们优化SQL的时候,会习惯去查看实际执行计划COST所占的开销比例,从而判断性能开销最大的SQL语句。当然大多数时候,这也是正确的。我们先来看看这个案例吧,如下所示,这个存储过程的部分实际执行计划如下(实际执行计划实在太长,无法全部展现):

我们将实际执行计划保存为sqlplan类型的文件(Execution Plan Files),然后用Plan Explorer展现出来,如下所示,Est Cost% 和 Est CPU  Cost% 显示第一个SQL语句是整个存储过程里面开销消耗最大的SQL语句。然后去测试验证,发现这个SQL不是开销最大的SQL,也就是说执行计划欺骗了我们,实际上,下面Est Cost %为13.3的SQL才是性能开销最大的SQL

从实际执行计划中找到elapsed time最长的SQL,这个SQL才是真正影响性能的SQL语句,然后查看这个SQL语句,发现其查询条件(WHERE)使用了自定义标量函数(因为修改业务逻辑,查询条件添加了自定义函数过滤数据),然而这个从实际执行计划去看也是看不出问题的,因为这个自定义标量函数哪怕调用了几十万次,它的开销代价在实际执行计划中并没有呈现出来。具体原因截取“SQL SERVER中用户定义标量函数(scalar user defined function)的性能问题“中的一段翻译如下:

翻译:

但是需要再次注意,执行计划在欺骗你,首先,它意味着只调用了UDF一次,其实不是这样。其次,从成本(Cost)来看,你可能会认为0%是向下舍入影响,因为单次执行函数的开销如此之小,以至于执行100,000次的成本也很小。但如果你检查执行计划的功能迭代器的属性,你会发现所有的操作代价和子树代价实际的估计为0,这是一个最糟糕的谎言。因为它可能不只是为了欺骗我们,而是SQL SERVER为了欺骗它自己。实际上是查询优化器认为调用函数的成本为0,因此它生成的所有执行计划都是基于调用UDF是免费的。其结果是即使调用标量UDF的代价非常昂贵,查询优化器也不会考虑优化它。

其实又单独总结一下这个问题,是因为人们或多或少受习惯性思维的影响,哪怕我之前多次遇到这种案例,但是在调优过程中,我还是会习惯性按照实际执行计划的COST比例去定位性能开销大的SQL语句,直到我通过验证推翻了这个判断,然后通过elapsed time最长的SQL语句才定位到开销最大的SQL。所以在调优、优化过程中,一定要多方位着手,反复推敲验证,不能被经验主义牵着鼻子走!

SQL Server实际执行计划COST"欺骗"案例的更多相关文章

  1. SQL Server 优化-执行计划

    对于SQL Server的优化来说,优化查询可能是很常见的事情.由于数据库的优化,本身也是一个涉及面比较的广的话题, 因此本文只谈优化查询时如何看懂SQL Server查询计划.毕竟我对SQL Ser ...

  2. 了解Sql Server的执行计划

    前一篇总结了Sql Server Profiler,它主要用来监控数据库,并跟踪生成的sql语句.但是只拿到生成的sql语句没有什么用,我们可以利用这些sql语句,然后结合执行计划来分析sql语句的性 ...

  3. SQL SERVER 2012 执行计划走嵌套循环导致性能问题的案例

    开发人员遇到一个及其诡异的的SQL性能问题,这段完整SQL语句如下所示: declare @UserId             INT declare @PSANo              VAR ...

  4. 程序员眼中的 SQL Server-执行计划教会我如何创建索引?

    先说点废话 以前有 DBA 在身边的时候,从来不曾考虑过数据库性能的问题,但是,当一个应用程序从头到脚都由自己完成,而且数据库面对的是接近百万的数据,看着一个页面加载速度像乌龟一样,自己心里真是有种挫 ...

  5. SQL Server-执行计划教会我如何创建索引

    先说点废话 以前有 DBA 在身边的时候,从来不曾考虑过数据库性能的问题,但是,当一个应用程序从头到脚都由自己完成,而且数据库面对的是接近百万的数据,看着一个页面加载速度像乌龟一样,自己心里真是有种挫 ...

  6. Sql Server中执行计划的缓存机制

    Sql查询过程 当执行一个Sql语句或者存储过程时, Sql Server的大致过程是 1. 对查询语句进行分析,将其生成逻辑单元,并进行基本的语法检查 2. 生成查询树(会将查询语句中所有操作转换为 ...

  7. SQL Server控制执行计划

    为了提高性能,可以使用提示(hints)特性,包含以下三类: 查询提示:(query hints)告知优化器在整个查询过程中都应用某个提示 关联提示:(join hints)告知优化器在查询的特定部分 ...

  8. sql server 根据执行计划查询耗时操作

    with QS as( select cp.objtype as object_type, /*类型*/ db_name(st.dbid) as [database], /*数据库*/ object_ ...

  9. sql server 2008 执行计划

    SSMS允许我们查看一个图形化的执行计划(快捷键Ctrl+L)

随机推荐

  1. [Swift]LeetCode676. 实现一个魔法字典 | Implement Magic Dictionary

    Implement a magic directory with buildDict, and search methods. For the method buildDict, you'll be ...

  2. [Swift]LeetCode724. 寻找数组的中心索引 | Find Pivot Index

    Given an array of integers nums, write a method that returns the "pivot" index of this arr ...

  3. 【Impala篇】---Hue从初始到安装应用

    一.前述 Cloudera公司推出,提供对HDFS.Hbase数据的高性能.低延迟的交互式SQL查询功能.基于Hive使用内存计算,兼顾数据仓库.具有实时.批处理.多并发等优点 是CDH平台首选的PB ...

  4. 关于ML.NET v0.6的发布说明

    ML.NET 0.6版本提供了几项令人兴奋的新增功能: 用于构建和使用机器学习模型的新API 我们主要关注的是发布用于构建和使用模型的新ML.NET API的第一次迭代.这些新的,更灵活的API支持新 ...

  5. 带着新人学springboot的应用07(springboot+RabbitMQ 下)

    说一两句废话,强烈推荐各位小伙伴空闲时候也可以写写自己的博客!不管水平高低,不管写的怎么样,不要觉得写不好或者水平不够就不写了(咳,我以前就是这样的想法...自我反省!). 但是开始写博客之后,你会发 ...

  6. Spring Boot2.0 静态资源被拦截问题

    在Spring Boot2.0+的版本中,只要用户自定义了拦截器,则静态资源会被拦截.但是在spring1.0+的版本中,是不会拦截静态资源的. 因此,在使用Spring Boot2.0+时,配置拦截 ...

  7. [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义

    前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine  ,既然是虚拟机, ...

  8. Spring Boot 2.x (八):日志框架的使用

    我们为啥要用日志? 最初我们开始接触Java的时候,我们通常会使用System.out.println()将我们想要知道的信息打印到控制台. 但是,如果在服务器上我们去运行我们的Java程序,这个时候 ...

  9. c#中的Unity容器

    DIP是依赖倒置原则:一种软件架构设计的原则(抽象概念).依赖于抽象不依赖于细节 IOC即为控制反转(Inversion of Control):传统开发,上端依赖(调用/指定)下端对象,会有依赖,把 ...

  10. C#工具:利用HttpClient调用WebApi

    可以利用HttpClient来进行Web Api的调用.由于WebA Api的调用本质上就是一次普通的发送请求与接收响应的过程, 所有HttpClient其实可以作为一般意义上发送HTTP请求的工具. ...