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]