为什么我的查询突然比昨天慢?


75

[薪水]

(检查一项)

[ ] Well trained professional, [ ] Casual reader, [ ] Hapless wanderer,

我有一个(选中所有适用项)

[ ] query [ ] stored procedure [ ] database thing maybe  

运行良好(如果适用)

[ ] yesterday [ ] in recent memory [ ] at some point 

但现在突然变慢了。

我已经检查过以确保它未被阻止,并且它不是某些长期运行的维护任务,报告或其他带外流程的受害者。

有什么问题,我应该怎么做,我可以提供什么信息以获得帮助?

[*Insert appropriate closing remarks*]

Answers:


88

亲爱的[您的名字在这里]!

哦,不,我很遗憾听到这个消息!让我们从一些基础知识开始,让您精打细算。

您遇到的事情称为参数嗅探

这是一个解决怪异问题的出路。这个名字从舌头上滚了下来。就像德语中的松鼠一词一样。

通常是你的朋友。

当查询命中您的服务器时,必须编译一个计划。为了稍后节省时间和资源,将根据该参数将导致您的代码处理并返回的估计行来缓存执行计划。

描绘这种情况的最简单方法是想象一个存储过程,该过程需要从两个不平衡的总体中计数。

例如:

  • 穿着没有受伤的CrossFit衬衫的人:零

  • 穿CrossFit衬衫的人在畏缩时畏缩:全部

显然,该代码的一次执行将比另一次执行更多的工作,而您要执行完全不同数量的工作的查询计划看起来将完全不同。

我要面对什么?

这是发现,测试和修复的真正困难的问题。

  • 很难找到,因为它不会持续发生
  • 很难测试,因为您需要知道哪些参数导致了不同的计划
  • 很难修复,因为有时需要查询和索引调整
  • 很难修复,因为您可能无法更改查询或索引
  • 很难解决,因为即使您更改查询或索引,它也可能会回来

快速修复

有时,您所需要的只是一点点的清晰度。确切地说,您的计划缓存可以。

如果是存储过程

尝试跑步EXEC sys.sp_recompile @objname = N'schema.procname'。这将导致该过程在下次运行时重新编译新计划。

无法解决的问题:

  • 当前正在运行的进程。

这不能保证什么:

  • 重新编译后运行的下一个进程将使用为您提供良好计划的参数。

您也可以指向sp_recompile一个表或视图,但是请注意,所有与该表或视图相关的代码都将重新编译。这会使问题变得更加困难。

如果是参数化查询

你的工作有点困难。您需要跟踪SQL句柄。您不想释放整个计划缓存-就像sp_recompile对表或视图使用一样,您可能会触发(哈哈哈)很多意外的后果。

确定该命令的最简单方法是运行sp_BlitzWho *!有一个称为“修复参数嗅探”的列,该列具有从缓存中删除单个计划的命令。但是,这具有与重新编译相同的缺点。

无法解决的问题:

  • 当前正在运行的进程。

这不能保证什么:

  • 重新编译后运行的下一个进程将使用为您提供良好计划的参数。

我仍然需要帮助!

我们将需要以下内容:

  • 好的查询计划(如果可能)
  • 错误的查询计划
  • 使用的参数
  • 有疑问的查询
  • 表和索引定义

获取查询计划和查询

如果查询正在运行,则可以使用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';

您应该从任何这些中看到非常相似的输出。同样,邀请计划中的蓝色可疑蓝色查询列是您的朋友。

坚果

共享计划的最简单方法是使用粘贴计划 *,或将XML转储到pastebin中。要做到这一点,请单击那些邀请蓝色clicky列之一。您的查询计划应出现在新的SSMS选项卡中。

坚果

如果您对共享公司代码和查询不满意,可以使用Sentry One的免费Plan Explorer工具来匿名化您的计划。请记住,这会使获得帮助变得更加困难-匿名代码很难阅读和弄清楚。

我们讨论的所有这些工具都应返回查询文本。您无需在这里做任何其他事情。

获取参数要困难一些。如果您使用的是Plan Explorer,则在底部有一个选项卡可以为您列出所有选项。

坚果

如果使用的是sp_BlitzCache *,则有一个可单击的列,该列为您提供存储过程的执行语句。

坚果

获取表和索引定义

您可以轻松地右键单击SSMS来编写脚本。

坚果

如果您想一次获得所有内容,则直接将sp_BlitzIndex *指向表可以提供帮助。

EXEC dbo.sp_BlitzIndex @DatabaseName = 'StackOverflow2010',
                       @SchemaName = 'dbo',
                       @TableName = 'Users';

这将为您提供表定义(尽管不是create语句),并为所有索引创建语句。

收集这些信息并将其添加到您的问题中应该可以使人们获得足够的信息来帮助您,或者为您指明正确的方向。

我想自己做!

好吧,酷。我为你感到高兴。你这个疯子。

人们认为他们可以“修正”参数嗅探的方式有很多:

但是这些实际上只是以不同的方式禁用了参数嗅探。这并不是说他们无法解决问题,只是他们并没有真正找到根本原因。

这是因为找到根本原因通常很困难。您必须寻找那些讨厌的“计划质量问题”。

从快速计划与慢速计划开始,寻找类似的差异:

  • 使用的索引
  • 加盟订单
  • 串行与并行

还要寻找使您的代码对参数嗅探敏感的其他运算符:

  • 查询
  • 排序
  • 联接类型
  • 内存授予(以及扩展,溢出)
  • 线轴

不要被搜寻,扫描,索引碎片或人们四处乱逛的任何杂物所累。

通常,存在一个非常基本的索引问题。有时代码需要重新编写一些。

如果您想了解有关参数嗅探的更多信息:

如果您正在阅读本文,并且认为我错过了链接或有用的工具,请发表评论。我会尽力使它保持最新状态。



28

参数嗅探不是查询性能变化的唯一可能原因。以下任何常见原因都可能显示相同的症状:

  1. 数据分布/数量已更改,跨越了优化器搜索树决策临界点
  2. 索引/文件碎片化
  3. 统计信息已更新/添加/删除,或者由于数据更改而变得过时和误导
  4. Windows内存利用率已更改
  5. 事务日志已满且未截断,导致重复的物理文件扩展
  6. 架构已更改-索引/索引视图/列/约束已添加,已修改或已删除,数据类型已更改等
  7. 跟踪标志设置已更改
  8. Windows更新已应用
  9. 数据库或服务器设置已更改
  10. 服务器CU级别已更改
  11. 客户端应用程序会话设置已更改

此列表中的项目6-11仅在采取某些明确的措施后才能发生。我想您打算排除这些,但是经历挑战的人很多时候并不知道其他人进行了更改,因此在您踏上清除计划缓存条目的路径之前,值得检查一下。


1
感谢Paul的编辑。@sp_BlitzErik-我的目的不是就特定主题提供建议,只是为了提高对它们的存在的认识,可能值得一试。这绝不意味着削弱您的出色职位。您处理的参数深度,专业且幽默。我喜欢阅读。我只想确保如果这里的某个人访问了此帖子,且标题醒目之后,他/她就会意识到其他可能的原因。恕我直言,它为您的帖子增加了价值,但如果您仍然希望我删除它,请告诉我。
SQLRaptor

一点都不。我绝不会要求别人删除不正确或有害的答案。我仍然认为您可以添加一些细节,但这最终取决于您。
Erik Darling

10

只是为了增加现有答案,以防万一,当第二天“突然”查询行为有所不同时,请检查:

  • 自上次以来,已使用表的方案是否发生变化?对于SSMS,可以在对象资源管理器中右键单击服务器,然后选择Reports → Standard Reports → Schema Changes History
  • 物品计数是否急剧增加?当使用的表中有很多数据时,查询可能会慢很多。
  • 是否有其他人在与您同时使用数据库?也许选择不干扰彼此工作的时隙。
  • 系统统计数据如何?也许服务器正在热运行并且正在节流CPU,或者硬盘驱动器空间不足或交换不足。也许还有另一个硬件问题,例如服务器机房中的火灾或洪水。

7

另一种可能性是,您的基础架构团队正在使用VMware上的vMotion之类的工具,而支持SQL实例的VM在主机之间无缝移动,而DBA却不知道。

当您的基础架构外包时,这是一个真正的问题。。。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.