我有一个针对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分钟,而开始运行需要一个半小时才运行。数据库的其余部分运行正常。我已经从通常会在其中运行的sproc中取出了此查询,并以相同的慢度在带有硬编码参数变量的SSMS中运行了该查询。
奇怪的是,当我使用将不相关的子查询放入临时表中,然后使用该子查询代替子查询,即可正常运行。另外(这对我来说是最奇怪的),如果我将这段代码添加到查询的末尾,则查询运行良好:
and t.name like '%'
我已经得出结论(可能是错误的)从这些小实验中得知,变慢的原因是由于SQL的缓存执行计划是如何设置的-当查询有些不同时,它必须创建一个新的执行计划。
我的问题是这样的:当曾经快速运行的查询突然在深夜开始运行,并且除此查询外,其他都没有受到影响,如何解决该问题以及如何防止将来发生?我怎么知道SQL在内部做的事情使其变得如此缓慢(如果运行了错误的查询,我可以得到它的执行计划,但它不会运行-也许预期的执行计划会给我一些东西?)?如果此问题与执行计划有关,那么如何避免SQL认为真正糟糕的执行计划是个好主意?
另外,这不是参数嗅探的问题。我以前见过这种情况,不是这样,因为即使我在SSMS中对变量进行硬编码,性能仍然很慢。
#1 楼
当曾经快速运行的查询突然在半夜开始缓慢运行并且除此查询外没有其他影响,我该如何解决它...?
您可以先检查执行计划是否仍在缓存中。检查
sys.dm_exec_query_stats
,sys.dm_exec_procedure_stats
和sys.dm_exec_cached_plans
。如果错误的执行计划仍被缓存,则您可以对其进行分析,还可以检查执行状态。执行状态将包含逻辑读取,CPU时间和执行时间等信息。这些可以强有力地表明问题出在哪里(例如,大扫描与阻塞)。有关如何解释数据的说明,请参见识别问题查询。另外,这不是参数嗅探的问题。我以前见过这种情况,事实并非如此,因为即使我在SSMS中对变量进行硬编码,性能仍然很慢。
我不相信。 SSMS中的硬编码变量不能证明过去的错误执行计划没有针对偏斜的输入进行编译。请阅读“参数嗅探,嵌入和RECOMPILE选项”以获取有关该主题的非常好的文章。应用速度慢,SSMS快速吗?了解性能奥秘
是另一个很好的参考。
我从这些小实验得出的结论(可能是错误的)是,放慢速度的原因是由于如何设置SQL的缓存执行计划-当查询是几乎没有什么不同,它必须创建一个新的执行计划。
可以很容易地对其进行测试。
SET STATISTICS TIME ON
将显示编译与执行时间。 SQL Server:统计性能计数器还将显示编译是否存在问题(坦率地说,我认为这不太可能)。但是,您可能会遇到类似的问题:查询授权门。有关详细信息,请阅读了解SQL Server内存授予。如果您的查询在没有可用内存的时刻请求大笔授权,它将不得不等待,并且对于应用程序而言,这一切都将视为“执行缓慢”。分析等待信息统计信息将揭示情况是否正确。
有关度量值和查找内容的更一般性讨论,请参见如何分析SQL Server性能
#2 楼
这是在SQL Server中运行复杂查询的祸根。幸运的是,这种情况很少发生。查看查询的查询计划(运行缓慢时)。我猜想您会发现一个嵌套循环联接在没有联接索引的表上发生一次或多次。这确实减慢了速度。为了快进,解决此问题的方法是带有提示。在查询末尾添加以下内容:
OPTION (MERGE JOIN, HASH JOIN)
过去,这通常已经为我解决了此问题。
可能是什么发生的情况是,对表的细微更改(或对临时空间的可用性)导致SQL优化更喜欢较慢的联接算法。这可能是非常微妙和突然的。创建临时表时,优化器会提供有关该表的更多信息(例如其大小),因此它可以生成更好的计划。
评论
实际上,执行计划使用的是嵌套循环联接。但是,当我按照您的建议放置提示时,出现以下错误:“查询处理器由于此查询中定义的提示而无法生成查询计划。重新提交查询时不指定任何提示,也无需使用SET FORCEPLAN。当然,当我添加OPTION(LOOP JOIN)时,它将创建一个执行计划,但运行缓慢仍然存在问题。你遇到这个问题了吗?看起来它需要循环连接。
–特雷弗
2014年4月4日20:36
@特雷弗。 。不,我实际上还没有看到这个问题。也许您的查询正在执行一些非等联接(不使用等号),并且优化器必须在此使用嵌套循环联接。
–戈登·利诺夫(Gordon Linoff)
2014年4月4日20:40
#3 楼
通常它是导致这种问题的缺少索引。我通常要做的是使用SQL Management Studio运行查询并启用“包括实际执行计划(CTRL + M)”并找出哪个联接占最大比例。
应用程序并不关注瓶颈,但是您只需查看结果即可“迅速”找到它。
示例:
评论
索引不会突然“丢失”,因此尽管这可能会提高性能,但不能解释问题
–家禽
16 Dec 14'在5:01
#4 楼
我最近也遇到了同样的问题,这使我进入了此页面。@MartinSmith在建议更新您的统计信息并解释计划时遇到了麻烦。我想补充一点,您还应该尝试确保正在运行的作业/查询可能会导致锁定,从而减慢响应时间。
在我看来,罪魁祸首是工作收集表统计。由于某种原因,它没有在应有的窗口中完成,并在用户恢复后继续运行。我找到了进程,将其终止,查询又开始响应。
希望对其他人有所帮助
评论
您能否在此处共享查询计划(慢速计划):brentozar.com/pastetheplan