getdate()
je runtime konstantní funkce
a je vyhodnocen pouze jednou za odkaz na funkci, proto
SELECT GETDATE()
FROM SomeBigTable
vrátí stejný výsledek pro všechny řádky bez ohledu na to, jak dlouho trvá spuštění dotazu.
Mezi těmito dvěma je však rozdíl. Jako první používá proměnnou a plán je zkompilován před přiřazením proměnné k SQL Server bude (v případě absence rekompilace) předpokládat, že bude vráceno 30 % řádků. Tento odhad může způsobit, že použije jiný plán než druhý dotaz.
Něco, co je třeba mít na paměti při používání GETDATE()
přímo ve filtru je to, že vyhodnocuje GETDATE()
v době kompilace a poté je možné, že se selektivita dramaticky změní, aniž by se dotaz nebo data změnily, aby spustily rekompilaci. V níže uvedeném příkladu proti tabulce s 1 000 řádky vede dotaz pomocí proměnné k plánu s odhadem 300 řádků a úplnému prohledání tabulky, zatímco dotaz s vloženým voláním funkce odhaduje 1 řádek a provádí vyhledávání záložek. To je přesné při prvním běhu, ale při druhém běhu se kvůli plynutí času nyní všechny řádky kvalifikují a skončí to provedením 1 000 takových náhodných vyhledávání.
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]