当我将值设置为变量时,为什么我的 SQL 语句的运行时间会延长 N 倍?
我想说的第一件事是,这并不是我想要实现的目标。我已经简化了这个查询很多,以便更清楚地表达我的问题。
我在表 (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 秒内得到结果。
当使用变量而不是将值硬编码到需要更长时间的地方时,是否有原因?我对此完全感到困惑,非常感谢任何帮助。
谢谢!
克里斯托弗·霍斯
The first thing i would like to say is that this is not exactly what I am trying to achieve. I have dumbed down this query A LOT to get my question across more clearly.
I have a nonclustered index on a table (CallDetail) on two values, TermDate (int) and SourceSystemID (int). To be complete, I will include the precise definition of the index here:
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]
The problem that I am having is that when I run two nearly identical queries against this table, I don't get the same results (not to be confused with result set). The first query runs in less than one second and returns about 10,000 rows. The second query, when executed, continues to run until I cancel it after about 30 minutes.
Query 1 (~1 second):
SELECT
*
FROM
CallDetail
WHERE
CallDetail.TermDate >= 1101221 AND
SourceSystemID = 1
Query 2 (>30 minutes):
DECLARE @TermDate AS INT
SET @TermDate = 1101221
SELECT
*
FROM
CallDetail
WHERE
CallDetail.TermDate >= @TermDate AND
SourceSystemID = 1
Something I would like to note is that the query execution plan tells me to 'include' all the columns of this table in the index. I find that to be completely wrong. I would also like to note that if i only select TermDate and SourceSystemID instead of * that I get results in about 1 seconds.
Is there a reason that when using a variable instead of hard coding a value into the where that it is taking so much longer? I am completely stumped on this and any help would be very much appreciated.
Thanks!
Christopher Haws
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好的,我用我的查询重现了这种情况:
在阅读了 marc_s 的帖子后,我这样做了:
一切又变得很快了!
OK, I reproduced the situation with my query:
After reading up on the post by marc_s, I did this:
And everything was fast again!
您很可能正遭受参数嗅探和此处 。
您可以比较两个查询的查询计划吗?固定值的还是带参数的?他们给你的实际执行计划是一样的吗?
只需记住在运行之间进行适当的“清理”并发出
DBCC FREEPROCCACHE
,以便两者不会相互影响......You're most likely suffering from parameter sniffing and here.
Can you compare the query plans for both your queries? The one with the fixed value vs. the one with the parameter? Do they give you the same actual execution plan?
Just remember to do a proper "cleanup" and issue
DBCC FREEPROCCACHE
between runs so that the two don't influence one another...更新
鉴于这些评论,我被难住了。你说你简化了细节来解释问题,可能是其中一些细节导致了问题。您是否在上面显示的确切示例中看到了相同的问题?
我见过包含强制转换或转换的更复杂的查询也有类似的问题——这是你简化的事情之一吗?
或者也许是 Marc 建议的参数嗅探。
原始答案
这是因为它必须将列表中的每个值转换为 int 类型(TermDate 列必须是其他列。)
在第一个查询中,优化器很聪明,知道它可以转换常量到列的类型并执行此操作。
此外,当它必须为每一行进行转换时,它不能使用索引。
将此行更改
为与列相同的类型,您会很高兴。
UPDATE
Given the comments, I'm stumped. You say you have dumbed down the details to explain the problem, it could be that some of those details are causing the problem. Are you seeing the same issues with the exact examples you show above?
I've seen more complicated queries that contain cast or convert have similar issues -- is this one of the things you dumbed down?
Or maybe it is Parameter Sniffing as Marc suggests.
Original Answer
This is because it has to cast each value in the columns table to type int (the TermDate column must be something else.)
In the first query the optimizer is smart and knows it can cast the constant to a the type of the column and does so.
Also, it can't use the index when it has to cast for every row.
Change this line
To the same type as the column and you will be happy.