4

我在 Sql Server 2008 上有这样的查询:

DECLARE @START_DATE DATETIME
SET @START_DATE = GETDATE()

SELECT * FROM MY_TABLE
WHERE TRANSACTION_DATE_TIME > DATEADD(MINUTE, -1440, @START_DATE)

在您在上面看到的选择查询中,SqlServer 是否优化查询以便不一次又一次地计算 DATEADD 结果。或者将 DATEADD 结果存储在临时变量上是我自己的责任吗?

4

3 回答 3

10

被视为运行时常量的SQL Server 函数只计算一次。GETDATE()就是这样一个函数,DATEADD(..., constant, GETDATE())也是一个运行时常量。通过将实际的函数调用留在查询中,您可以让优化器查看实际使用的值(而不是变量值嗅探),然后它可以相应地调整其基数估计,可能会提出更好的计划。

另请阅读:对查询性能不佳进行故障排除:基数估计期间的常量折叠和表达式评估

@马丁史密斯

您可以运行此查询:

set nocount on;
declare @known int;
select @known = count(*) from sysobjects;
declare @cnt int = @known;
while @cnt = @known
    select @cnt = count(*) from sysobjects where getdate()=getdate()
select @cnt, @known;

在我的情况下,22 秒后它达到边界情况并退出循环。重要的是循环以@cnt 退出。有人会期望,如果getdate()每行评估 ,那么我们会得到一个与正确的@known 计数不同的@cnt,但不是 0。当循环存在时 @cnt 为零的事实表明每个都getdate()被评估一次,然后是相同的常量值用于每一行 WHERE 过滤(匹配无)。我知道一个正面的例子并不能证明一个定理,但我认为这个案例已经足够确凿了。

于 2011-09-04T18:33:18.033 回答
8

令人惊讶的是,我发现使用 GETDATE() 内联似乎比预先执行这种类型的计算更有效。

DECLARE @sd1 DATETIME, @sd2 DATETIME;
SET @sd1 = GETDATE();

SELECT * FROM dbo.table
WHERE datetime_column > DATEADD(MINUTE, -1440, @sd1)

SELECT * FROM dbo.table
WHERE datetime_column > DATEADD(MINUTE, -1440, GETDATE())

SET @sd2 = DATEADD(MINUTE, -1440, @sd1);

SELECT * FROM dbo.table
WHERE datetime_column > @sd2;

如果您检查这些计划,中间查询将始终以最低的成本出现(但并不总是最低的经过时间)。当然,它可能取决于您的索引和数据,并且您不应该基于一个查询做出任何假设,即相同的抢先优化将适用于另一个查询。我的直觉是不执行任何内联计算,而是使用@sd2上面的变化......但我了解到我不能一直相信我的直觉,我不能根据我经历过的行为做出一般假设特定场景。

于 2011-09-04T18:12:27.590 回答
3

它只会执行一次。您可以通过检查执行计划(“Compute Scalar”->Estimated Number of execution == 1)来仔细检查它

于 2011-09-04T18:01:01.157 回答