【问题标题】:Query optimization with variables使用变量进行查询优化
【发布时间】:2016-01-06 12:10:38
【问题描述】:

首先,如果这个问题是常见问题,我深表歉意……我似乎无法找到正确的搜索字词……

我有一个有点大的表,它有一个递增的 ID 和一个插入的 datetime 值。它上面有几个索引,包括ID 上的主键和插入时间和ID 上的非聚集索引。因此,当我编写如下查询时,速度非常快:

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

但是,如果我改变 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。但是,第二个查询改为对主键(即 ID)执行 2 scans

所以,我的问题有两个:

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

【问题讨论】:

  • Parameters 生成的独立查询完全不同,SQL Server 可以使用常量而不是变量进行更准确的估计,从而得出更好的计划。您可以尝试使用 Plan Guides 强制使用不同的计划
  • 简单的一点是,根据数据范围查询优化器必须在索引搜索和索引扫描之间进行选择。
  • @lad2025,虽然我不认为参数链接与我的场景有任何关系(这不是存储过程),但听起来 option(recompile) 应该在 MSSQL 2008 和更新...这至少意味着有一个合理的解决方案向前发展...
  • 这不是存储过程。局部变量具有与上面链接中描述的相同的行为。想一想,当你在你的案例中传递一个常量时,一天范围查询优化器知道它很窄并使用索引搜索。当您传递变量时,它会尝试制定通用执行计划。
  • 看到this和你的问题完全一样

标签: tsql sql-server-2005


【解决方案1】:

通过使用局部变量,您正遭受隐式 OPTION (OPTIMIZE FOR UNKNOWN) 的困扰。请参阅this link 了解更多信息。优化器无法通过参数嗅探局部变量,而是使用基于平均值的通用计划。使用常量时,它能够使用更好的统计数据并通过使用搜索进行优化。

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

【讨论】:

  • 这似乎正是如此。只需将变量更改为存储过程的输入参数即可获得正确的优化。
  • “基于平均数的一般计划” - 这些平均数是多少?什么的平均值?
  • 平均值基于表格上统计信息的密度向量分量。 SQL Server 使用它来尝试创建一个“足够好”但参数信息不完整的执行计划。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-25
  • 1970-01-01
  • 2013-10-14
  • 1970-01-01
  • 2013-01-14
  • 2012-08-16
相关资源
最近更新 更多