SQL Server是否在select查询中优化DATEADD计算?

时间:2011-09-04 17:49:49

标签: sql sql-server dateadd

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

DECLARE @START_DATE DATETIME
SET @START_DATE = GETDATE()

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

在上面看到的select查询中,SqlServer是否会优化查询,以便不会反复计算DATEADD结果。或者我自己有责任将DATEADD结果存储在临时变量上吗?

3 个答案:

答案 0 :(得分:10)

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

另请阅读:Troubleshooting Poor Query Performance: Constant Folding and Expression Evaluation During Cardinality Estimation

@Martin Smith

您可以运行此查询:

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(),那么我们将得到@cnt与正确的@known计数不同,但不是0.当循环存在时@cnt为零的事实显示每个{{1评估过一次,然后对每一行使用相同的常量值WHERE过滤(匹配无)。我知道一个正面的例子不能证明一个定理,但我认为这个案例已经足够确凿。

答案 1 :(得分: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变体......但我已经知道我不能一直相信自己的直觉而且我无法做出一般假设我在特定场景中遇到的行为。

答案 2 :(得分:3)

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