Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Qualcuno potrebbe spiegare la differenza tra due query?

getdate() è un runtime funzione costante e viene valutato solo una volta per riferimento di funzione, motivo per cui

SELECT GETDATE()
FROM SomeBigTable

restituirà lo stesso risultato per tutte le righe indipendentemente dal tempo necessario per l'esecuzione della query.

C'è una differenza tra i due però. Poiché il primo utilizza una variabile e il piano viene compilato prima che la variabile venga assegnata a SQL Server (in assenza di una ricompilazione) presuppone che verrà restituito il 30% delle righe. Questa ipotesi potrebbe far sì che utilizzi un piano diverso rispetto alla seconda query.

Qualcosa da tenere a mente con l'utilizzo di GETDATE() direttamente in un filtro è che valuta GETDATE() in fase di compilazione e successivamente è possibile che la selettività cambi drasticamente senza che la query oi dati cambino per attivare una ricompilazione. Nell'esempio seguente rispetto a una tabella di 1.000 righe, la query che utilizza una variabile porta a un piano con una stima di 300 righe e una scansione completa della tabella mentre la query con la chiamata di funzione incorporata stima 1 riga ed esegue una ricerca di segnalibro. Questo è accurato nella prima manche ma nella seconda manche a causa del passare del tempo ora tutte le file si qualificano e finisce per eseguire 1.000 di queste ricerche casuali.

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]