我首先要说的是,这并不是我想要实现的目标。我已经愚弄了这个问题很多,以便更清楚地解决我的问题。
我在表(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]
我遇到的问题是,当我对这个表运行两个几乎相同的查询时,我得不到相同的结果(不要与结果集混淆)。第一个查询在不到一秒的时间内运行并返回大约10,000行。第二个查询在执行时继续运行,直到我在大约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秒内得到结果。
是否有理由在使用变量而不是将值硬编码到需要更长时间的位置?我完全被这个难以接受,任何帮助都将非常感激。
谢谢!
Christopher Haws
答案 0 :(得分:5)
好的,我用我的查询重现了这个情况:
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)
一切都很快了!
答案 1 :(得分:2)
您最有可能患parameter sniffing和here。
您可以比较两个查询的查询计划吗?具有固定值的那个与具有参数的那个?他们会给你相同的实际执行计划吗?
请记住做一次正确的“清理”并在两次运行之间发出DBCC FREEPROCCACHE
,这样两者就不会相互影响......
答案 2 :(得分:1)
更新
鉴于这些评论,我很难过。你说你已经愚弄了细节来解释这个问题,可能是其中一些细节导致了这个问题。您是否在上面显示的确切示例中看到了相同的问题?
我看到包含演员或转换的更复杂的查询有类似的问题 - 这是你愚蠢的事情之一吗?
或许这可能是Marc建议的参数嗅探。
原始答案
这是因为它必须将列表中的每个值转换为int类型(TermDate列必须是其他内容。)
在第一个查询中,优化器是智能的,并且知道它可以将常量强制转换为列的类型,并且这样做。
此外,当必须为每一行进行强制转换时,它不能使用索引。
更改此行
DECLARE @TermDate AS INT
与列相同的类型,您会很高兴。