问题描述
当一个曾经运行速度很快的查询在半夜突然开始运行缓慢并且除了这个查询之外没有其他任何影响,我该如何解决它......?
您可以首先检查执行计划是否仍在缓存中。检查和。sys.dm_exec_query_stats_ 如果仍然缓存了错误的执行计划,您可以对其进行分析,还可以检查执行统计信息。执行统计信息将包含逻辑读取、cpu 时间和执行时间等信息。这些可以有力地表明问题所在(例如,大扫描与阻塞)。有关如何解释数据的说明,请参阅识别问题查询。sys.dm_exec_procedure_statssys.dm_exec_cached_plans
此外,这不是参数嗅探的问题。我以前见过,但事实并非如此,因为即使我在 SSMS 中对变量进行硬编码,我的性能仍然很慢。
我不相信。SSMS 中的硬编码变量并不能证明过去的错误执行计划不是针对倾斜的输入进行编译的。请阅读Parameter Sniffing, Embedding, and the RECOMPILE Options以获得关于该主题的非常好的文章。应用程序慢,SSMS 快?了解性能奥秘 是另一个很好的参考。
我从这些小实验中得出(也许是错误的)结论,减速的原因是由于 sql 的缓存执行计划是如何设置的——当查询有点不同时,它必须创建一个新的执行计划。
这可以很容易地测试。SET STATISTICS TIME ON将向您显示编译与执行时间。sql Server:Statistics性能计数器也会显示编译是否是一个问题(坦率地说,我觉得不太可能)。
但是,您可能会遇到类似的问题:查询授权门。有关详细信息,请阅读了解 sql Server 内存授予。如果您的查询在没有可用内存的情况下请求大笔授权,它将不得不等待,并且对于应用程序来说,这一切看起来都是“缓慢执行”。分析等待信息统计数据将揭示是否是这种情况。
解决方法
背景
我有一个针对 SQL Server 2008 R2 运行的查询,它连接和/或左连接大约 12 个不同的“表”。该数据库相当大,有许多超过 5000 万行的表和大约 300 个不同的表。这是一家在全国拥有 10 个仓库的大型公司。所有的仓库都对数据库进行读写。所以它很大而且很忙。
我遇到问题的查询如下所示:
select t1.something,t2.something,etc.
from Table1 t1
inner join Table2 t2 on t1.id = t2.t1id
left outer join (select * from table 3) t3 on t3.t1id = t1.t1id
[etc]...
where t1.something = 123
请注意,其中一个联接位于非相关子查询上。
问题是从今天早上开始,系统没有任何更改(我或我团队中的任何人都知道),通常需要大约 2 分钟才能运行的查询开始需要一个半小时才能运行 - 当它根本跑了。数据库的其余部分运行良好。我已经从它通常运行的存储过程中取出了这个查询,并且我已经在带有硬编码参数变量的 SSMS 中以同样的速度运行它。
奇怪的是,当我将不相关的子查询放入临时表中,然后使用它而不是子查询时,查询运行良好。此外(这对我来说是最奇怪的)如果我将这段代码添加到查询的末尾,查询运行良好:
and t.name like '%'
我从这些小实验中得出(也许是错误的)结论,减速的原因是由于 SQL 的缓存执行计划是如何设置的——当查询有点不同时,它必须创建一个新的执行计划。
我的问题是:当一个曾经快速运行的查询突然在半夜开始缓慢运行并且除了这个查询之外没有其他任何影响时,我该如何解决它以及如何防止它在未来发生? 我怎么知道 SQL 在内部做了什么让它变得这么慢(如果运行了错误的查询,我可以获得它的执行计划但它不会运行——也许预期的执行计划会给我一些东西?)?如果这个问题与执行计划有关,我如何让 SQL 不认为真正糟糕的执行计划是个好主意?
此外,这不是参数嗅探的问题。我以前见过,但事实并非如此,因为即使我在 SSMS 中对变量进行硬编码,我的性能仍然很慢。