2015-10-08 195 views
1

首先,我很抱歉,如果这个问题是很常见的。我似乎无法找到正确的字词进行搜索......查询优化

我有了一个增量有点大表ID和一个插入的值datetime。其上有几个索引,包括ID上的主键和插入时间和ID的非聚集索引。所以,当我写类似下面的查询,这是非常快:

select min(ID), max(ID) 
from tbl 
where inserted between '2015-10-07' and '2015-10-08' 

但是,如果我variablize where子句条件(如下),这是相当慢一点:

declare @sTime datetime, @eTime datetime 
select @sTime = '2015-10-07', @eTime = '2015-10-08' 

select min(ID), max(ID) 
from tbl 
where inserted between @sTime and @eTime 

当我看看两个查询计划,我发现显而易见的问题。第一个查询在插入的时间和ID的非聚集索引上使用单个seek。但是,第二个查询改为在主键上执行2 scans(这只是ID)。

所以,我的问题是双重的:

  1. 为什么SQL Server执行这些优化,并
  2. 我该如何解决?
+2

[参数](http://www.sommarskog.se/query-plan-mysteries.html#varparamreplace)得到的独立查询是完全不同的,SQL Server可以使用常量进行**更准确的估计的变量**,因此得出一个更好的计划。您可以尝试强制使用与[计划指南](http://www.sommarskog.se/query-plan-mysteries.html#planguides) – lad2025

+0

不同的计划。简单的说就是根据数据范围查询优化器必须在索引查找与索引扫描。 – lad2025

+0

@ lad2025,虽然我不认为参数链接与我的场景(这不是存储过程)有任何关系,但它听起来像'选项(重新编译)'应该在MSSQL 2008和更新的版本中工作...这至少意味着有一个合理的解决方案前进...... – chezy525

回答

3

通过使用局部变量,您正患有隐含的OPTION (OPTIMIZE FOR UNKNOWN)。有关更多信息,请参见this link。优化器不能参数嗅探局部变量,并且正在使用基于平均值的总体规划。当使用常量时,它可以使用更好的统计数据并通过使用搜索进行优化。

要解决此问题,您可能需要创建存储过程并提供参数而不是变量。您可能还需要添加OPTION (RECOMPILE)提示以获得与使用常量时类似的优化。否则,你将受到第一次执行期间被嗅探的任何参数的影响。

+0

这看起来确实如此。只需将变量更改为存储过程的输入参数即可实现正确的优化。 – chezy525

+0

“基于平均值的总体规划” - 这些平均值是多少?什么的平均值? – BornToCode

+0

平均值基于表中统计信息的density_vector分量。 SQL Server使用它来尝试创建一个“足够好”的执行计划,同时具有不完整的参数信息。 – CElliott