SQL Server optimise-t-il le calcul DATEADD dans une requête select?

J'ai une requête comme celle-ci sur Sql Server 2008:

DECLARE @START_DATE DATETIME SET @START_DATE = GETDATE() SELECT * FROM MY_TABLE WHERE TRANSACTION_DATE_TIME > DATEADD(MINUTE, -1440, @START_DATE) 

Dans la requête select que vous voyez ci-dessus, SqlServer optimise la requête afin de ne pas calculer le résultat DATEADD encore et encore. Ou est-ce ma responsabilité de stocker le résultat DATEADD sur une variable temporaire?

    Étonnamment, j'ai trouvé que l'utilisation de GETDATE () inline semble être plus efficace que d'effectuer ce type de calcul à l'avance.

     DECLARE @sd1 DATETIME, @sd2 DATETIME; SET @sd1 = GETDATE(); SELECT * FROM dbo.table WHERE datetime_column > DATEADD(MINUTE, -1440, @sd1) SELECT * FROM dbo.table WHERE datetime_column > DATEADD(MINUTE, -1440, GETDATE()) SET @sd2 = DATEADD(MINUTE, -1440, @sd1); SELECT * FROM dbo.table WHERE datetime_column > @sd2; 

    Si vous vérifiez les plans sur ceux-ci, la requête du milieu sortira toujours avec le coût le plus bas (mais pas toujours le time écoulé le plus bas). Bien sûr, cela peut dépendre de vos index et données, et vous ne devriez pas faire d'hypothèses basées sur une requête que la même optimization préemptive fonctionnera sur une autre requête. Mon instinct serait de ne pas effectuer de calculs en ligne, et d'utiliser plutôt la variante @sd2 ci-dessus … mais j'ai appris que je ne peux pas faire confiance à mon instinct tout le time et je ne peux pas faire d'hypothèses générales basées sur le comportement expérience dans des scénarios particuliers.

    Les fonctions SQL Server considérées comme des constantes d'exécution ne sont évaluées qu'une seule fois. GETDATE() est une telle fonction et DATEADD(..., constant, GETDATE()) est également une constante d'exécution. En laissant l'appel de la fonction réelle dans la requête, vous laissez l'optimiseur voir quelle valeur sera réellement utilisée (par opposition à un sniff de valeur variable) et ensuite il peut ajuster ses estimations de cardinalité en conséquence, éventuellement avec un meilleur plan.

    Lisez également ceci: Dépannage des performances médiocres des requêtes: évaluation constante du pliage et de l'expression lors de l'estimation de la cardinalité .

    @ Martin Smith

    Vous pouvez exécuter cette requête:

     set nocount on; declare @known int; select @known = count(*) from sysobjects; declare @cnt int = @known; while @cnt = @known select @cnt = count(*) from sysobjects where getdate()=getdate() select @cnt, @known; 

    Dans mon cas, après 22 secondes, il a heurté le cas limite et la boucle est sortie. La chose importante est que la boucle s'est terminée avec @cnt zéro . On pourrait s'attendre à ce que si getdate() est évalué par ligne alors nous obtiendrions un @cnt différent du nombre correct de @known, mais pas de 0. Le fait que @cnt soit zéro quand la boucle existe montre que chaque getdate() été évalué une fois et ensuite la même valeur constante a été utilisée pour chaque ligne WHERE filtrage (correspondant aucun). Je suis conscient qu'un exemple positif ne prouve pas un théorème, mais je pense que le cas est assez concluant.

    Il sera exécuté une seule fois. Vous pouvez le vérifier en vérifiant le plan d'exécution ("Compute Scalar" -> Estimated Number of execution == 1)