一次存储过程参数嗅探定位流程总结

昨天一开发同事反馈一个存储过程很慢,但是重编译后,存储过程就很快了。了解基本情况后,初步判断是参数嗅探问题。那么如何诊断定位、分析问题呢?下面简单介绍一下这次参数嗅探问题定位的流程过程。

首先查看该存储过程的执行计划相关信息:

如下截图所示,此存储过程是2018-09-12 9:03:01缓存的,最后一次执行是2018-09-14 08:58,而且自上次缓存后,执行了24875次。从这里我们基本判断该存储过程一直在重用缓存的执行计划,而且没有产生重编译现象。

SELECT  d.object_id ,
        d.database_id ,

        OBJECT_NAME(object_id, database_id) ‘proc name‘ ,

        d.cached_time ,

        d.last_execution_time ,

        d.total_elapsed_time ,

        d.total_elapsed_time / d.execution_count AS [avg_elapsed_time] ,

        d.last_elapsed_time ,

        d.execution_count

FROM    sys.dm_exec_procedure_stats AS d

WHERE   OBJECT_NAME(object_id, database_id) = ‘sp_GetOTList‘

ORDER BY [total_worker_time] DESC;  

然后我们使用下面脚本找到该存储过程的实际执行计划,将存储过程的执行计划的XML内容拷贝到Plan Explorer工具。生成比较清晰、详细的执行计划图。

SELECT
        d.object_id ,

        DB_NAME(d.database_id) DBName ,

        OBJECT_NAME(object_id, database_id) ‘SPName‘ ,

        d.cached_time ,

        d.last_execution_time ,

        d.total_elapsed_time/1000000    AS total_elapsed_time,

        d.total_elapsed_time / d.execution_count/1000000 

                                        AS [avg_elapsed_time] ,

        d.last_elapsed_time/1000000        AS last_elapsed_time,

        d.execution_count ,

        d.total_physical_reads ,

        d.last_physical_reads ,

        d.total_logical_writes ,

        d.last_logical_reads ,

        et.text SQLText ,

        eqp.query_plan executionplan

FROM    sys.dm_exec_procedure_stats AS d

CROSS APPLY sys.dm_exec_sql_text(d.sql_handle) et

CROSS APPLY sys.dm_exec_query_plan(d.plan_handle) eqp

WHERE   OBJECT_NAME(object_id, database_id) = ‘sp_GetOTList‘

ORDER BY [total_worker_time] DESC;

如下截图所示,我们可以清晰的找到Est Cost、 Est Cpu Cost、 Est IO Cost等高的SQL语句(其实这个是实际执行计划,而不是预估的执行计划),

然后重点研究、对比, 然后使用WITH(RECOMPILE)重新执行该存储过程,生成新的执行计划,然后按照上面方式将存储过程执行计划的XML拷贝到Plan Explorer工具里面。 然后我们可以对比、研究看看到底出现了什么情况

旧的实际执行计划

 

如上截图所示,开销最大的SQL语句的实际执行计划如上所示,注意开销占比最大的地方。 下面截图是Nested Loops里面循环的次数(迭代次数20次),也是我们

对比执行计划需要重点关注的地方

新的实际执行计划

新的执行计划中,可以看到旧执行计划开销最大的SQL语句在整体开销的占比减少了很多,但是该语句的新旧执行计划是一样的。唯一不同的就是两个Nested Loops里面循环的次数不一样。这个就是产生性能差异的地方,如果对嵌套循环连接不太熟悉,可以参考一下下面这段内容:

Nested Loops也称为嵌套迭代,它将一个联接输入用作外部输入表(显示为图形执行计划中的顶端输入),将另一个联接输入用作内部(底端)输入表。外部循环逐行消耗外部输入表。内部循环为每个外部行执行,在内部输入表中搜索匹配行。最简单的情况是,搜索时扫描整个表或索引;这称为单纯嵌套循环联接。如果搜索时使用索引,则称为索引嵌套循环联接。如果将索引生成为查询计划的一部分(并在查询完成后立即将索引破坏),则称为临时索引嵌套循环联接。

旧执行计划:

嵌套循环次数:20* 30

嵌套循环次数:20*20

新执行计划:

嵌套循环次数: 1* 1

嵌套循环次数: 1* 1

那么为什么产生这个差异,就是因为存储过程里面一段SQL语句使用了存储过程参数,而恰巧里面那个表按照这个字段的数据分布很不均衡。所以当存储过程按照第一次传入的参数生成执行计划并缓存下来,而按照那个参数生成的执行计划并不是一直都是最优执行计划,那么就导致了性能问题出现了,这也就是参数嗅探问题。

解决方法

 

在SQL语句后面使用HINT提示来解决参数嗅探,本想在对应的SQL语句后面使用OPTION (RECOMPILE) ,但是考虑此存储过程调用频繁,而且同事极力推荐使用提示OPTION (OPTIMIZE FOR UNKNOWN).修改过后,性能测试效果也确实显著。

原文地址:https://www.cnblogs.com/kerrycode/p/9650629.html

时间: 2024-11-10 11:12:13

一次存储过程参数嗅探定位流程总结的相关文章

SQL Server 参数嗅探问题

本文非原创,来源于网络,作为记录为以后查看 http://mysql.taobao.org/monthly/2016/10/10/ 摘要 MSSQL Server参数嗅探既是一个涉及知识面非常广泛,又是一个比较难于解决的课题,即使对于数据库老手也是一个比较头痛的问题.这篇文章从参数嗅探是什么,如何产生,表象是什么,会带来哪些问题,如何解决这五个方面来探讨参数嗅探的来龙去脉,期望能够将SQL Server参数嗅探问题理清楚,道明白. 什么参数嗅探 当SQL Server第一次执行查询语句或存储过程

理解性能的奥秘——应用程序中慢,SSMS中快(4)——收集解决参数嗅探问题的信息

本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(3)--不总是参数嗅探的错 前面已经提到过关于存储过程在SSMS中运行很快,但在应用程序中运行很慢的可能原因:因为ARITHABORT的不同选项会导致不同的缓存词目,另外由于SQL Server使用了参数嗅探导致获得了不同的执行计划. 虽然已经说明了这个现象的原因,但是还没解释:如何定位和解决这个问题?到目前为止,大家都知道了如何快速处理,如果这个问题很紧急,可以直接使用: EX

(4.13)参数嗅探

1 --参数嗅探 Parameter Sniffing 2013-2-8 2 3 --当使用存储过程的时候,总是要使用到一些变量.变量有两种,一种 4 --是在存储过程的外面定义的.当调用存储过程的时候,必须要给他代入 5 --值.这种变量,SQL在编译的时候知道他的值是多少. 6 7 --例如: 8 USE [AdventureWorks] 9 GO 10 DROP PROC Sniff 11 GO 12 CREATE PROC Sniff(@i INT) 13 AS 14 SELECT CO

视图,触发器,事务,存储过程,函数与流程控制,索引

一.视图 1.什么是视图 虚拟表:在硬盘中没有的,通过查询在内存中拼接的表 视图:通过查询得到一张虚拟表,保存下来,下次可直接使用 2.为什么要用视图 如果要频繁使用一张虚拟表,可以不用重复查询 3.如何用视图 create view teacher2course as select * from teacher inner join course on teacher.tid = course.teacher_id; 4.删除视图 drop view teacher2course; 5.强调

参数嗅探(Parameter Sniffing)(1/2)

这个问题会在参数话的SQL语句(例如存储过程)与SQL Server里的计划缓存机制结合的时候会出现.这个文章分为2个部分,第1部分会介绍下参数嗅探(Parameter Sniffing)的概况,第2部分我们介绍下如何解决这个问题. 什么是参数嗅探(Parameter Sniffing) 在SQL Server里当你执行参数话的SQL查询时,查询优化器会基于第一个提供的参数值编译执行计划.然后生成的执行计划在计划缓存里缓存作为后期的重用.这就是说SQL Server后续会直接重用这个计划,而不管

SQL Server 查询优化(测试02)参数嗅探-执行计划选择

最近常看到"参数嗅探"这个词,看了几篇文章,于是就自己摸索做个测试来加深印象! 去官网下载了数据库:AdventureWorks2012 直接测试吧! 找几个熟悉的表关联起来,用ProductID作为条件找到两个ID返回行数相差较大的值. ProductID=870(4688行) ProductID=897(2行) [测试一] --先清空计划缓存 DBCC FREEPROCCACHE --执行前先打开计数器监控查看(分开执行以下查询) select sdh.SalesOrderID,s

理解性能的奥秘——应用程序中慢,SSMS中快(5)——案例:如何应对参数嗅探

本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(4)--收集解决参数嗅探问题的信息 首先我们需要明白,参数嗅探本身不是问题,而是一个特性,避免SQL Server做出盲目的假设,从而产生次优查询计划.但是有些情况下,参数嗅探却会带来负面影响.通常有下面三种典型的情况: 查询使用的参数嗅探完全不合适.也就是说,查询计划对于这次执行是合适的,但是对于下一次执行就可能不合适. 应用程序中存在特定的调用模式,而且与其他大部分调用模式差

参数嗅探(Parameter Sniffing)(2/2)

在参数嗅探(Parameter Sniffing)(1/2)里,我介绍了SQL Server里参数嗅探的基本概念和背后的问题.如你所见,当缓存的计划被SQL Server盲目重用时,会带来严重的性能问题.今天我会向你展示下如何处理这个问题,即使用不同的技术克服它. 索引(Index) 上次我们讨论造成参数嗅探问题的根源是:在执行计划里,SQL 语句有时会产生书签查找,有时会产生表/聚集索引扫描.如果你能在数据库里修改索引,解决这个问题的最简单方法就是提供查询列对应的覆盖非聚集索引.这里我们就要包

理解性能的奥秘——应用程序中慢,SSMS中快(3)——不总是参数嗅探的错

本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(2)--SQL Server如何编译存储过程 在我们开始深入研究如何处理参数嗅探相关的性能问题之前,由于这个课题过于广泛,所以首先先介绍一些跟参数嗅探没有直接关系的内容,但是又会导致语句在SSMS和应用程序中存在性能差异的情况. 替换变量和参数: 前面已经接触过,但是在这里对其进行扩展.有时会看到论坛上有人说,某个存储过程很慢,但是把相同的语句提取出来单独执行就很快.真相就是:语