Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Quelqu'un pourrait-il expliquer la différence entre deux requêtes ?

getdate() est un environnement d'exécution fonction constante et n'est évalué qu'une seule fois par référence de fonction, c'est pourquoi

SELECT GETDATE()
FROM SomeBigTable

renverra le même résultat pour toutes les lignes, quel que soit le temps d'exécution de la requête.

Il y a cependant une différence entre les deux. Comme le premier utilise une variable et que le plan est compilé avant que la variable ne soit affectée à SQL Server (en l'absence d'une recompilation) supposera que 30 % des lignes seront renvoyées. Cette supposition peut l'amener à utiliser un plan différent de celui de la deuxième requête.

Quelque chose à garder à l'esprit avec l'utilisation de GETDATE() directement dans un filtre est qu'il évalue GETDATE() au moment de la compilation et par la suite, il est possible que la sélectivité change radicalement sans que la requête ou les données ne changent pour déclencher une recompilation. Dans l'exemple ci-dessous sur une table de 1 000 lignes, la requête utilisant une variable conduit à un plan avec environ 300 lignes et une analyse complète de la table, tandis que la requête avec l'appel de fonction intégré estime 1 ligne et effectue une recherche de signet. Ceci est exact lors de la première exécution, mais lors de la deuxième exécution, en raison du passage du temps, toutes les lignes sont désormais qualifiées et cela finit par effectuer 1 000 recherches aléatoires de ce type.

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]