欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识
原文出处: 潇湘隐者

昨天一开拓同事反馈一个存储进程很慢,可是重编译后,存储进程就很快了。相识根基环境后,劳务派遣管理系统,劈头判定是参数嗅探问题。那么如何诊断定位、阐明问题呢?下面简朴先容一下这次参数嗅探问题定位的流程进程。

首先查察该存储进程的执行打算相关信息:

如下截图所示,此存储进程是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;

独一差异的就是两个N  <a href=昆山软件定制开拓 ested Loops内里轮回的次数纷歧样" class="aligncenter size-full wp-image-29910" title="73542-20180915122952304-450151863" src="/uploads/allimg/c180920/153IX15KVF-13249.png" />

然后我们利用下面剧本找到该存储进程的实际执行打算,将存储进程的执行打算的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东西内里。 然后我们可以比拟、研究看看到底呈现了什么环境 

旧的实际执行打算

独一差异的就是两个N  <a href=昆山软件定制开拓 ested Loops内里轮回的次数纷歧样" class="aligncenter size-full wp-image-29911" title="73542-20180915122953278-794176314" src="/uploads/allimg/c180920/153IX15L5W0-24628.png" />

如上截图所示,开销最大的SQL语句的实际执行打算如上所示,留意开销占比最大的处所。 下面截图是Nested Loops内里轮回的次数(迭代次数20次),也是我们

比拟执行打算需要重点存眷的处所

独一差异的就是两个N  <a href=昆山软件定制开拓 ested Loops内里轮回的次数纷歧样" class="aligncenter size-full wp-image-29912" title="73542-20180915122954047-1523417624" src="/uploads/allimg/c180920/153IX15M1R0-34138.png" />

新的实际执行打算

独一差异的就是两个N  <a href=昆山软件定制开拓 ested Loops内里轮回的次数纷歧样" class="aligncenter size-full wp-image-29913" title="73542-20180915122954929-1501614810" src="/uploads/allimg/c180920/153IX15M40P-4J08.png" />

新的执行打算中,可以看到旧执行打算开销最大的SQL语句在整体开销的占比淘汰了许多,可是该语句的新旧执行打算是一样的。独一差异的就是两个Nested Loops内里轮回的次数纷歧样。这个就是发生机能差此外处所,假如对嵌套轮回毗连不太熟悉,可以参考一下下面这段内容:

Nested Loops也称为嵌套迭代,它将一个联接输入用作外部输入表(显示为图形执行打算中的顶端输入),将另一个联接输入用作内部(底端)输入表。外部轮回逐行耗损外部输入表。内部轮回为每个外部行执行,劳务派遣管理系统,在内部输入表中搜索匹配行。最简朴的环境是,搜索时扫描整个表或索引;这称为纯真嵌套轮回联接。假如搜索时利用索引,则称为索引嵌套轮回联接。假如将索引生成为查询打算的一部门(并在查询完成后当即将索引粉碎),则称为姑且索引嵌套轮回联接。

旧执行打算: 

  • 嵌套轮回次数:20* 30
  • 嵌套轮回次数:20*20
  • 新执行打算:

  • 嵌套轮回次数: 1* 1 
  • 嵌套轮回次数: 1* 1
  • 独一差异的就是两个N  <a href=昆山软件定制开拓 ested Loops内里轮回的次数纷歧样" class="aligncenter size-full wp-image-29914" title="73542-20180915122955885-1402476655" src="/uploads/allimg/c180920/153IX15MT20-521U.png" />独一差异的就是两个N  <a href=昆山软件定制开拓 ested Loops内里轮回的次数纷歧样" class="aligncenter size-full wp-image-29915" title="73542-20180915122956520-268708499" src="/uploads/allimg/c180920/153IX15N050-DE3.png" />

    那么为什么发生这个差别,就是因为存储进程内里一段SQL语句利用了存储进程参数,而刚巧内里谁人表凭据这个字段的数据漫衍很不平衡。所以当存储进程凭据第一次传入的参数生成执行打算并缓存下来,而凭据谁人参数生成的执行打算并不是一直都是最优执行打算,那么就导致了机能问题呈现了,这也就是参数嗅探问题。 

    办理要领

    在SQL语句后头利用HINT提示来办理参数嗅探,本想在对应的SQL语句后头利用OPTION (RECOMPILE) ,可是思量此存储进程挪用频繁,并且同事积极推荐利用提示OPTION (OPTIMIZE FOR UNKNOWN).修改事后,机能测试结果也确实显著。