将常量移动到where子句中的变量会显着改变执行计划吗?

时间:2018-04-18 23:36:27

标签: sql-server parameters sql-execution-plan

我为复杂视图创建了一个索引。在Sql Server管理工作室中运行以下查询需要0到几秒。查询计划显示99%的成本是在我为主要大表创建的索引的索引查找中。 (总子树成本为7.5)

select * from ComplexView where id = 10000 and theDate = '1/1/2018'

但是,以下查询

declare @id int = 10000, @theDate datetime = '1/1/2018'
select * from ComplexView where id = @id and theDate = @theDate

需要很长时间(3到10分钟),查询计划捕获显示57%的成本在主要大表上的表扫描上(加上10%过滤器和14%哈希匹配和17%排序,总子树成本为260)。

1 个答案:

答案 0 :(得分:3)

第一个查询将根据文字10000'1/1/2018'的值以及相关表格的直方图统计信息编制查询计划。

第二个基本上是"优化未知"因为在编译时认为参数的值是未知的。当您使用本地变量时,SQL Server无法再使用直方图。相反,它使用统计对象的密度向量信息。

这是已知的和预期的行为(尽管如果你不知道它可能会令人惊讶)。

您启用了显示两个查询的实际执行计划,发现他们有不同的计划。

如果您碰巧首先使用'典型的'值(基于所涉及的列的分布),您将获得适用于过滤器的大多数值的缓存计划。

假设您的统计信息是最新的,请尝试以下操作:

declare @id int = 10000, @theDate datetime = '1/1/2018'
select * from ComplexView 
where id = @id and theDate = @theDate
option(recompile)

你有更合理的计划吗?

使用option(recompile)是其中之一'它取决于'解答!如果查询是报告查询(我的意思是它运行时间相对较长且不经常运行),请考虑添加它。它告诉SQL Server不要缓存计划并在每次执行时重新编译新计划。它的缺点是您不会在缓存中看到该计划,并且在每次执行时支付计划编译的成本(与长时间运行的查询相比相对较小)。

如果它是关键报告查询,那么我会添加option(recompile)以确保您永远不会得到不合适的查询计划。

相关问题