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

发布于 2024-10-09 04:15:00 字数 1184 浏览 0 评论 0原文

我想说的第一件事是,这并不是我想要实现的目标。我已经简化了这个查询很多,以便更清楚地表达我的问题。

我在表 (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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

美男兮 2024-10-16 04:15:00

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

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)

一切又变得很快了!

OK, I reproduced the situation with my query:

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

After reading up on the post by marc_s, I did this:

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

And everything was fast again!

心作怪 2024-10-16 04:15:00

您很可能正遭受参数嗅探此处

您可以比较两个查询的查询计划吗?固定值的还是带参数的?他们给你的实际执行计划是一样的吗?

只需记住在运行之间进行适当的“清理”并发出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...

樱花落人离去 2024-10-16 04:15:00

更新

鉴于这些评论,我被难住了。你说你简化了细节来解释问题,可能是其中一些细节导致了问题。您是否在上面显示的确切示例中看到了相同的问题?

我见过包含强制转换或转换的更复杂的查询也有类似的问题——这是你简化的事情之一吗?

或者也许是 Marc 建议的参数嗅探。


原始答案

这是因为它必须将列表中的每个值转换为 int 类型(TermDate 列必须是其他列。)

在第一个查询中,优化器很聪明,知道它可以转换常量到列的类型并执行此操作。

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

将此行更改

 DECLARE @TermDate AS INT

为与列相同的类型,您会很高兴。

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

 DECLARE @TermDate AS INT

To the same type as the column and you will be happy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文