什么东西导致了执行计划的严重错误——需要更新统计信息吗?

    原文出处:What caused that plan to go horribly wrong – should you update statistics?

    由于本人确实遇到过这类问题,但是基于水平和经历,不打算重复造轮子,所以把大牛的文章翻译一下以供大家参考。以下是译文:

过去几年里,我(作者)遇到这类情景:

    有一个存储过程在大部分时间里面都运行得很好,但是突然就不行了。其性能出现断崖式下降。你不知道原因,不过有人说:“一定是统计信息的问题”。确实,如果你有大量时间,检查执行计划的时候,会发现估计行数和实际行数有很大出入。OK,应该就是统计信息的问题了。

    但是,也许不是。 首先要知道,存储过程、使用 sp_executesql 执行的参数化语句和客户端提交的预准备(prepared)语句都重用缓存的执行计划。这些执行计划使用称为“参数嗅探(parameter sniffing)”的技术来定义。参数嗅探本身不是什么问题,但是在后续使用相同语句、存储过程执行时就可能成为问题。如果某些语句的执行计划根据参数只返回1行数据,那么执行计划可能很简单——使用一个非聚集索引和书签查找来查找数据。但是相同的语句在再次执行但参数会导致返回数千行数据时,这个执行计划可能就不够合理了。

    执行计划并不存储在磁盘中,当缓存中不存在执行计划时才会创建。所以可能会有很多原因导致缓存中找不到所需的执行计划。如果刚好出现了一个不典型的参数集作为执行计划生成的第一组参数(准确来说应该是“已失效”),那么意味着这个不常用的参数的执行计划会一直被使用,而且这种执行计划往往是不够高效的。同时,此时你研究执行计划时也会发现估计行数和实际行数的巨大差异。这个并不是统计信息的问题。

    如果确实是统计信息的问题,那么要怎么做呢?

    通常来说就是UPDATE STATISTICS 表名或UPDATE STATISTICS 表名 索引名(执行计划用到的索引)。然后再次执行存储过程。这次准确了。所以你会觉得是统计信息问题。

    但是你可能只看到了服务器端的统计信息已经更新,当你更新统计信息,SQL Server通常会使执行计划失效。因此在缓存中的执行计划也会失效。当重新执行的时候,就会创建新的执行计划,这个执行计划会使用当前参数来生成。

    那么对于这类问题要如何操作?

    首先,不要动不动就先更新统计信息。如果有一个存储过程出现了这个问题,应该考虑先进行重编译,看看是否能得到更好的执行计划。重编译(如使用sp_recompile)会使得缓存中的对应执行计划失效。这个操作不仅快速简单,并且还能验证是否统计信息出问题。如果此时有效,那么可能要考虑改进代码。关于这部分可以参考一下这篇文章:Stored procedures, recompilation and .NetRocks。如果无效,那么才考虑更新统计信息。不过,首先要做的是确保代码的编译值和执行值相同。可以通过包含实际执行计划的属性窗口查找:


    如果使用正确值还是不行,那可能就是统计信息问题,但是统计信息往往被诟病,可是通常不是真正原因,执行计划才是。

    当更新统计信息时执行计划是否总会失效?答案是否定的。关于这个问题,可以参考两篇文章:http://erinstellato.com/2012/01/statistics-recompilations/ 和 Statistics and Recompilations, Part II。简单来说,从SQL 2012开始,更新统计信息并不引起执行计划失效。


总结

    在遇到相似现象时,应该先检查是否出现参数嗅探问题,而不是马上更新统计信息。另外注意除了存储过程之外,使用 sp_executesql 执行的参数化语句和客户端提交的预准备(prepared)语句都可能出现。

    另一篇本人(译者)的系列文章:理解性能的奥秘——应用程序中慢,SSMS中快(1)——简介

   

猜你喜欢

转载自blog.csdn.net/DBA_Huangzj/article/details/79522554