优化器似乎对varchar参数的空能力感到困惑,我不知道为什么。我正在使用SQL Server 2008 btw。所有被查询的列都被编入索引。 TDate列是一个聚集的分区索引。 FooValue列是索引的,不可为空的列。SQL Server 2008存储过程 - 优化器认为我的参数可以为空
例子:
CREATE PROCEDURE dbo.MyExample_sp @SDate DATETIME, @EDate DATETIME, @FooValue VARCHAR(50)
AS
SET NOCOUNT ON
--To avoid parameter spoofing/sniffing
DECLARE @sDate1 DATETIME, @eDate1 DATETIME
SET @sDate1 = @sDate
SET @eDate1 = @eDate
SELECT
fd.Col1,
fd.Col2,
fd.TDate,
fl.FooValue,
fd.AccountNum
FROM dbo.FooData fd
INNER JOIN dbo.FooLookup fl
ON fl.FL_ID = fd.FL_ID
WHERE fd.TDate >= @sDate1
AND fd.TDate < @eDate1
AND fl.FooValue = @FooValue
运行此作为查询按预期工作。所有索引都是搜索引擎,没有欺骗等。通过执行sproc执行此操作需要20倍的时间 - 相同的查询 - 相同的参数。但是,如果我做出以下更改(非常最后一行),一切都可以再次发挥作用。
CREATE PROCEDURE dbo.MyExample_sp @SDate DATETIME, @EDate DATETIME, @FooValue VARCHAR(50)
AS
SET NOCOUNT ON
--To avoid parameter spoofing/sniffing
DECLARE @sDate1, @eDate1
SET @sDate1 = @sDate
SET @eDate1 = @eDate
SELECT
fd.Col1,
fd.Col2,
fd.TDate,
fl.FooValue,
fd.AccountNum
FROM dbo.FooData fd
INNER JOIN dbo.FooLookup fl
ON fl.FL_ID = fd.FL_ID
WHERE fd.TDate >= @sDate1
AND fd.TDate < @eDate1
AND fl.FooValue = ISNULL(@FooValue, 'testthis')
这就好像优化器对参数是否为空或者是不是很困惑?另外,向参数添加默认值也没有什么区别。除非我使用= isnull(@参数,'一些常量'),否则它仍然需要永久运行。
我很高兴我明白了这一点。但是,我想了解为什么会发生这种情况,以及是否有更加优雅的方式来解决问题。
变量*为*可空。你的问题是为什么一个可为空的变量影响查询计划?或者为什么变量被认为是可空的? – 2012-07-27 21:51:37
我想这应该是后者。现在我已经遇到了这个问题,我可以明白为什么这个变量被认为是空的(当然我可以传入一个空值)。 但是,为什么查询计划全部搞砸了让我感到困惑。 PS:有没有更好的方法来告诉SQL一个变量不能为空?感谢你的协助! – maplemale 2012-07-27 22:05:00
一种方法是将查询写为动态SQL,并将变量硬编码为字符串中的值。当你运行字符串时,它会在那个时候被编译,所以它应该选择最佳的查询计划。 – 2012-07-27 22:24:25