SQL Server,索引和参数的特殊情况

时间:2009-10-23 14:20:30

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

我有一张桌子,我们称之为History。主键(也称为聚簇索引)称为HIST_ID。该表在开发DB中有大约2300行。现在考虑以下两个查询:

查询1:

declare @x int
set @x = 14289

select * from History where hist_id=@x

查询2:

declare @x int
set @x = 14289

select * from History where hist_id=@x or @x is null

唯一的区别是最后的or @x is null。然而,第一个查询执行索引搜索,第二个 - 索引扫描。是什么给了什么?

先发制人的回复 - 不,选项(重新编译)没有帮助。

补充:我想要一些可靠的论证事实,而不是猜测。我自己可以猜出十几种可能的原因。但这里的真正的问题是什么?

3 个答案:

答案 0 :(得分:1)

我建议将计划与传入/使用的参数分开生成,因此实质上有一个要求(取决于@x的值)返回每一行。因此,查询计划正在处理它可以接收的参数的最坏情况。

e.g。如果@x的输入为null,则查询将被强制返回每一行,因为每一行都将满足始终返回true的文字方程/谓词。要使查询计划涵盖@x的每个值,它必须生成执行扫描的计划。

答案 1 :(得分:0)

我想优化器确定它是有益的。另一种方法是使用与编写

相同的计划
select * from History where hist_id=@x
union all
select * from History where @x is null

您可以用这种方式重写查询,但我很确定优化器能够自行完成此操作。你有多少个空值?

编辑:结果我误解了这个问题,并认为你想要WHERE(@x = hist_id或hist_id为null)。实际上你想要一个动态标准。查看this article。请注意,如果您指定WITH(RECOMPILE),那么您的查询应该在SQL2k8中工作,但由于一个讨厌的错误,此支持已被删除。

答案 2 :(得分:0)

当然是索引扫描。

聚簇索引扫描=表扫描,因为“@x IS NULL”没有合理的谓词。

参数化的缓存计划是通用的,适用于@x = NULL或@x = value。 如果你没有定义@x,你应该得到相同的计划。

如果编码“12345 IS NULL”,则会检测到并忽略它。

我找不到关于如何在查询计划中处理常量的博客文章。要点是它们是一般化的,并且不会发生短路以允许计划重用。