(检查一个)
[ ] Well trained professional,[ ] Casual reader,[ ] Hapless wanderer,
我有一个(检查所有适用的)
[ ] query [ ] stored procedure [ ] database thing maybe
运行正常(如果适用)
[ ] yesterday [ ] in recent memory [ ] at some point
但现在突然变慢了.
我已经检查过以确保它没有被阻止,并且它不是一些长期运行的维护任务,报告或其他带外过程的受害者.
问题是什么,我该怎么做,以及我可以提供哪些信息来获得帮助?
[*Insert appropriate closing remarks*]
解决方法
哦不,我很抱歉听到这个消息!让我们从一些基础开始,让你快速修复.
你遇到的事情叫做参数嗅探
这是一个解决wiggy奇怪问题的方法.这个名字从舌头上滚下来.就像德语中的松鼠一样.
它通常是你的朋友.
当查询命中您的服务器时,必须编译计划.为了以后节省时间和资源,将根据参数将导致代码处理和返回的估计行来缓存执行计划.
描述这种情况的最简单方法是想象一个存储过程需要从两个不平衡的人群中计算事物.
例如:
>穿着没有受伤的CrossFit衬衫的人:零
>穿着CrossFit衬衫的人在畏缩时会畏缩:全部
显然,该代码的执行必须比另一个执行更多的工作,并且您想要完成不同工作量的查询计划看起来完全不同.
我该反对什么?
这是一个真正难以找到,测试和修复的问题.
>很难找到,因为它不会一直发生
>测试很难,因为您需要知道哪些参数会导致不同的计划
>这很难修复,因为有时它需要查询和索引调整
>很难修复,因为您可能无法更改查询或索引
>这很难修复,因为即使您更改了查询或索引,它仍可能会回来
快速修复
有时候,你需要的只是一点点清晰度.或者说,您的计划缓存确实如此.
如果是存储过程
尝试运行EXEC sys.sp_recompile @objname = N’schema.procname’.这将导致程序在下次运行时重新编译新计划.
这不会解决的问题:
>当前正在运行它的进程.
这不保证:
>重新编译后运行的下一个进程将使用一个为您提供良好计划的参数.
您还可以在表或视图中指向sp_recompile,但要预先警告所有触及该表或视图的代码都将重新编译.这可能会使问题变得更加困难.
如果是参数化查询
你的工作有点困难.您需要跟踪sql句柄.您不想释放整个计划缓存 – 就像对表或视图使用sp_recompile一样,您可能会触发(哈哈哈)一堆意想不到的后果.
确定该命令的最简单方法是运行sp_BlitzWho *!有一个名为“fix parameter sniffing”的列,它有一个从缓存中删除单个计划的命令.但是,这与重新编译具有相同的缺点.
这不会解决的问题:
>当前正在运行它的进程.
这不保证:
>重新编译后运行的下一个进程将使用一个为您提供良好计划的参数.
我还需要帮助!
我们需要以下东西:
>如果可能的话,好的查询计划
>糟糕的查询计划
>使用的参数
>有问题的查询
>表和索引定义
如果查询正在运行,则可以使用sp_BlitzWho *或sp_WhoIsActive捕获当前正在执行的查询.
EXEC sp_BlitzWho; EXEC sp_WhoIsActive @get_plans = 1;
如果查询当前未在执行,您可以使用sp_BlitzCache *在计划缓存中检查它.
如果您使用的是sql Server 2016,并且启用了“查询存储”,则可以使用sp_BlitzQueryStore *.
EXEC dbo.sp_BlitzCache @StoredProcName = 'Your Mom'; EXEC dbo.sp_BlitzQueryStore @StoredProcName = 'Your Mom';
这些将帮助您跟踪存储过程的缓存版本.如果它只是参数化代码,那么您的搜索会更困难一些.但这可能会有所帮助:
EXEC dbo.sp_BlitzCache @QueryFilter = 'statement';
您应该看到其中任何一个的输出非常相似.同样,邀请酷蓝色clicky列的查询计划是你的朋友.
共享计划的最简单方法是使用Paste The Plan *,或将XML转储到pastebin中.要获得该功能,请单击其中一个邀请蓝色clicky列.您的查询计划应显示在新的SSMS选项卡中.
如果您对共享公司代码和查询非常敏感,可以使用Sentry One’s free Plan Explorer tool来匿名化您的计划.请记住,这会使得帮助变得更加困难 – 匿名代码更难以阅读和弄清楚.
我们谈到的所有这些工具都应该返回查询文本.你不需要在这里做任何其他事情.
获取参数有点困难.如果您使用的是Plan Explorer,则底部会显示一个标签,其中列出了全部内容.
如果您使用的是sp_BlitzCache *,则会有一个可单击的列,它为您提供存储过程的执行语句.
获取表和索引定义
您可以轻松地在SSMS中右键单击以编写内容.
如果你想一次性获得所有东西,sp_BlitzIndex *可以帮助你直接指向一张桌子.
EXEC dbo.sp_BlitzIndex @DatabaseName = 'StackOverflow2010',@SchemaName = 'dbo',@TableName = 'Users';
这将为您提供表定义(尽管不是作为创建语句),并为您的所有索引创建语句.
收集这些信息并将其添加到您的问题中应该可以为人们提供足够的信息来帮助您,或者为您指明正确的方向.
我想自己做!
好吧,很酷.我很高兴你.你疯了.
人们认为他们“修复”参数嗅探有很多方法:
> Recompile hints
> Optimize for unknown
>优化价值
但这些只是以不同的方式禁用参数嗅探.这并不是说他们无法解决问题,他们只是没有真正找到根本原因.
那是因为找到根本原因通常有点困难.你必须寻找那些讨厌的“计划质量问题”.
从快速与慢速计划开始,寻找以下差异:
>使用的索引
>加入订单
>串行与并行
还要查找使代码对参数嗅探敏感的不同运算符:
>查找
>排序
>加入类型
>记忆补助(以及扩展,溢出)
>线轴
不要过于局限于寻求与扫描,索引碎片或任何人们下摆和讨厌的货物崇拜.
通常,有一个非常基本的索引问题.有时代码需要一点重写.
如果您想了解有关参数嗅探的更多信息:
> Slow in the Application,Fast in SSMS? – Erland Sommarskog
>故障排除参数嗅探1,2,3 – Tara Kizer
> Why You’re Tuning Stored Procedures Wrong (the Problem with Local Variables) – Kendra Little
> How to Use Parameters Like a Pro and Boost Performance – Guy Glantser
> Parameter Sniffing,Embedding,and the RECOMPILE Options – 保罗怀特
如果您正在阅读本文,并且您认为我错过了链接或有用的工具,请发表评论.我会尽力保持最新状态.
*完全披露,我为这些开源脚本做出了贡献.他们是麻省理工学院的许可证和所有好东西,所以你不必担心你用它们做什么.