2

第一个查询是:

declare @myDate datetime = DATEADD(D,-2000,getdate())
SELECT * FROM [myTable]  
where CreatedDate >= @myDate

第二个查询是:

SELECT * FROM [myTable]  
where CreatedDate >= DATEADD(D,-2000,getdate())

我希望第一个查询可能会更快,因为“dateadd”函数只计算一次。但在实践中,这个查询都是相等的(2 秒,30 000 行)

4

3 回答 3

3

getdate()是一个运行时常量函数,每个函数引用只评估一次,这就是为什么

SELECT GETDATE()
FROM SomeBigTable

无论查询运行多长时间,都将为所有行返回相同的结果。

不过两者还是有区别的。由于第一个使用变量并且在将变量分配给 SQL Server 之前编译计划将(在没有重新编译的情况下)假设将返回 30% 的行。这种猜测可能会导致它使用与第二个查询不同的计划。

直接在过滤器中使用要记住的一点GETDATE()是,它在编译时进行评估GETDATE(),此后选择性可能会发生显着变化,而不会更改查询或数据以触发重新编译。在下面针对 1,000 行表的示例中,使用变量的查询会导致一个估计有 300 行和全表扫描的计划,而使用嵌入函数调用的查询估计 1 行并执行书签查找。这在第一次运行时是准确的,但在第二次运行时,由于时间的流逝,现在所有行都符合条件,最终会进行 1,000 次这样的随机查找。

USE tempdb;

CREATE TABLE [myTable]
(
CreatedDate datetime,
Filler char(8000) NULL
)

CREATE NONCLUSTERED INDEX ix ON [myTable](CreatedDate)

INSERT INTO [myTable](CreatedDate)
/*Insert 1 row that initially qualifies*/
SELECT DATEADD(D,-2001,getdate())
UNION ALL
/*And 999 rows that don't initially qualify*/
SELECT TOP 999 DATEADD(minute,1, DATEADD(D,-2000,getdate()))
FROM master..spt_values

EXEC('
DECLARE @myDate DATETIME = DATEADD(D,-2000,getdate())
SELECT * 
FROM [myTable]  
WHERE CreatedDate <= @myDate
')

EXEC('
SELECT * 
FROM [myTable]  
WHERE CreatedDate <= DATEADD(D,-2000,getdate())
')

RAISERROR ('Delay',0,1) WITH NOWAIT

WAITFOR DELAY '00:01:01'

EXEC('
DECLARE @myDate DATETIME = DATEADD(D,-2000,getdate())
SELECT * 
FROM [myTable]  
WHERE CreatedDate <= @myDate
')

EXEC('
SELECT * 
FROM [myTable]  
WHERE CreatedDate <= DATEADD(D,-2000,getdate())
')

DROP TABLE [myTable]
于 2012-03-28T10:45:41.990 回答
1

SQL 不会为每一行重新计算 DATEADD。无论哪种方式,它都会计算一次,然后对表中的行的结果进行比较。两种不同的方式,一种(可能不必要地)比另一种更冗长,但最终它们给出了相同的结果。

于 2012-03-28T10:36:46.010 回答
0

SQL 服务器优化器正在协助使后一个查询更优化。

看看查询计划

于 2012-03-28T10:42:31.580 回答