背景
我有一个针对 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
Run Code Online (Sandbox Code Playgroud)
请注意,其中一个连接位于不相关的子查询上。
问题是从今天早上开始,没有对系统进行任何更改(我或我团队中的任何人都知道),通常需要大约 2 分钟才能运行的查询,开始需要一个半小时才能运行——当它跑了。数据库的其余部分运行良好。我已经从它通常运行的 sproc 中取出了这个查询,并且我已经在 SSMS 中以相同的速度在带有硬编码参数变量的情况下运行它。
奇怪的是,当我将不相关的子查询放入临时表中,然后使用它而不是子查询时,查询运行良好。另外(这对我来说是最奇怪的)如果我将这段代码添加到查询的末尾,查询运行得很好:
and t.name like '%'
Run Code Online (Sandbox Code Playgroud)
我从这些小实验中得出结论(可能是错误的),速度变慢的原因是 SQL 的缓存执行计划是如何设置的——当查询有点不同时,它必须创建一个新的执行计划。
我的问题是:当一个曾经运行得很快的查询在半夜突然开始运行缓慢并且除了这个查询之外没有其他任何影响时,我该如何解决它以及如何防止它在未来发生? 我怎么知道 SQL 在内部做了什么使其如此缓慢(如果错误的查询运行,我可以获得它的执行计划但它不会运行——也许预期的执行计划会给我一些东西?)?如果这个问题与执行计划有关,我如何让 SQL 不认为真正糟糕的执行计划是个好主意?
此外,这不是参数嗅探的问题。我以前见过,但事实并非如此,因为即使我在 SSMS 中对变量进行硬编码,我的性能仍然很慢。