Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Könnte jemand den Unterschied zwischen zwei Abfragen erklären?

getdate() ist eine Laufzeitumgebung konstante Funktion und wird nur einmal pro Funktionsreferenz ausgewertet, weshalb

SELECT GETDATE()
FROM SomeBigTable

gibt dasselbe Ergebnis für alle Zeilen zurück, unabhängig davon, wie lange die Ausführung der Abfrage dauert.

Es gibt jedoch einen Unterschied zwischen den beiden. Da der erste eine Variable verwendet und der Plan kompiliert wird, bevor die Variable SQL Server zugewiesen wird, wird (in Ermangelung einer Neukompilierung) davon ausgegangen, dass 30 % der Zeilen zurückgegeben werden. Diese Vermutung kann dazu führen, dass ein anderer Plan als die zweite Abfrage verwendet wird.

Etwas, das bei der Verwendung von GETDATE() zu beachten ist direkt in einem Filter ist, dass es GETDATE() auswertet Zur Kompilierzeit und danach ist es möglich, dass sich die Selektivität drastisch ändert, ohne dass sich entweder die Abfrage oder die Daten ändern, um eine Neukompilierung auszulösen. Im Beispiel unten für eine Tabelle mit 1.000 Zeilen führt die Abfrage mit einer Variablen zu einem Plan mit geschätzten 300 Zeilen und einem vollständigen Tabellenscan, während die Abfrage mit dem eingebetteten Funktionsaufruf 1 Zeile schätzt und eine Lesezeichensuche durchführt. Dies ist beim ersten Durchlauf korrekt, aber im zweiten Durchlauf qualifizieren sich aufgrund des Zeitablaufs jetzt alle Zeilen und es werden 1.000 solcher zufälligen Suchen durchgeführt.

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]