当我将一个值设置为变量时,为什么SQL语句的运行时间要长N倍?

当我将一个值设置为变量时,为什么SQL语句的运行时间要长N倍?,sql,variables,indexing,long-integer,Sql,Variables,Indexing,Long Integer,我想说的第一件事是,这并不是我想要达到的目标。为了让我的问题更清楚地表达出来,我把这个问题简化了很多 我在CallDetail表上有一个非聚集索引,它有两个值,TermDate int和SourceSystemID int。为了完整起见,我将在这里包括索引的精确定义: CREATE NONCLUSTERED INDEX [CallDetail_TermDateSourceSystemID] ON [dbo].[CallDetail] ( [TermDate] ASC, [Sou

我想说的第一件事是,这并不是我想要达到的目标。为了让我的问题更清楚地表达出来,我把这个问题简化了很多

我在CallDetail表上有一个非聚集索引,它有两个值,TermDate int和SourceSystemID int。为了完整起见,我将在这里包括索引的精确定义:

CREATE NONCLUSTERED INDEX [CallDetail_TermDateSourceSystemID] ON [dbo].[CallDetail] 
(
    [TermDate] ASC,
    [SourceSystemID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
我遇到的问题是,当我对这个表运行两个几乎相同的查询时,我不会得到相同的结果,以免与结果集混淆。第一个查询在不到一秒钟的时间内运行,并返回大约10000行。第二个查询在执行时继续运行,直到我在大约30分钟后取消它

查询1~1秒:

SELECT
    *
FROM
    CallDetail
WHERE
    CallDetail.TermDate >= 1101221 AND
    SourceSystemID = 1
查询2>30分钟:

DECLARE @TermDate AS INT
SET @TermDate = 1101221

SELECT
    *
FROM
    CallDetail
WHERE
    CallDetail.TermDate >= @TermDate AND
    SourceSystemID = 1
我想指出的是,查询执行计划告诉我在索引中“包括”该表的所有列。我发现这是完全错误的。我还想指出,如果我只选择TermDate和SourceSystemID而不是*,我将在大约1秒内得到结果

当使用变量而不是将值硬编码到数据中时,是否有一个原因导致它花费的时间更长?我完全被这件事难住了,任何帮助都将不胜感激

谢谢

克里斯托弗·霍斯更新

考虑到这些评论,我被难住了。你说你已经简化了细节来解释问题,可能是这些细节导致了问题。你在上面的例子中看到了同样的问题吗

我见过包含cast或convert的更复杂的查询也有类似的问题——这是您忽略的问题之一吗

也可能是Marc建议的参数嗅探

原始答案

这是因为它必须强制转换columns表中的每个值才能键入int。TermDate列必须是其他列

在第一个查询中,优化器是智能的,知道它可以将常量转换为列的类型,并这样做

此外,当它必须为每一行强制转换时,它不能使用索引

换行

 DECLARE @TermDate AS INT

与本专栏相同的类型,您将很高兴。

您很可能患有和

您能否比较两个查询的查询计划?有固定值的那个和有参数的那个?他们给你的是相同的实际执行计划吗


只需记住进行适当的清理,并在运行之间发出DBCC FREEPROCCACHE,以便两者不会相互影响…

好的,我用我的查询再现了这种情况:

declare @a as int
set @a = 12972100
select * from MyTable where (MyColumn > @a)
在阅读了marc_s的文章后,我做了以下工作:

declare @a as int
set @a = 12972100
select * from MyTable where (MyColumn > @a) option (recompile)

一切又快了

TermDate列的数据类型是什么?@Lamak:op的帖子说TermDate int第二段,第一行让我们看看整个表的定义。我已经在自己的服务器上验证了这种行为。我有一个包含12000324条记录的表,它在整数上有一个非聚集索引。我做了同样的事情,我的查询来自Hi Hogan,TermDate是表中的INT类型。我想这可能是参数嗅探,但他描述问题的方式没有意义……这是100%正确的。我看到了与OP相同的行为。我有一个查询select*from MyTable,其中MyRow>12972100,我得到了1个plan。当我把号码改为2时,我得到了一个不同的计划。然而,当我使用变量时,第二个计划总是被使用@CHristopher Haws,阅读marc_在参数嗅探上发表的文章,你会明白的。