有人可以解释两个查询之间的区别吗?

时间:2012-03-28 10:32:30

标签: performance sql-server-2008 dateadd

第一个查询是:

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行)

3 个答案:

答案 0 :(得分:3)

getdate()是一个runtime constant function,每个函数引用只评估一次,这就是为什么

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]

答案 1 :(得分:1)

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

答案 2 :(得分:0)

SQL Server优化器正在协助使后一种查询更加优化。

查看query plan