getdate()
jest środowiskiem uruchomieniowym funkcja stała
i jest oceniany tylko raz na odwołanie do funkcji, dlatego
SELECT GETDATE()
FROM SomeBigTable
zwróci ten sam wynik dla wszystkich wierszy, niezależnie od tego, jak długo trwa zapytanie.
Jest jednak między nimi różnica. Ponieważ pierwszy korzysta ze zmiennej, a plan jest kompilowany przed przypisaniem zmiennej do SQL Server, przyjmie (w przypadku braku rekompilacji) zwrócenie 30% wierszy. To przypuszczenie może spowodować użycie innego planu niż drugie zapytanie.
Coś, o czym należy pamiętać przy użyciu GETDATE()
bezpośrednio w filtrze jest to, że oblicza GETDATE()
w czasie kompilacji i później istnieje możliwość radykalnej zmiany selektywności bez zmiany zapytania lub danych w celu wywołania ponownej kompilacji. W poniższym przykładzie w odniesieniu do tabeli zawierającej 1000 wierszy zapytanie używające zmiennej prowadzi do planu z szacowanymi 300 wierszami i pełnym skanowaniem tabeli, podczas gdy zapytanie z osadzonym wywołaniem funkcji szacuje 1 wiersz i wykonuje wyszukiwanie zakładek. Jest to dokładne w pierwszym przebiegu, ale w drugim przebiegu ze względu na upływ czasu teraz wszystkie wiersze kwalifikują się i kończy się to wykonaniem 1000 takich losowych wyszukiwań.
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]