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

Lorsque vous utilisez GETDATE() à de nombreux endroits, est-il préférable d'utiliser une variable ?

[REMARQUE :Si vous souhaitez voter contre cette réponse, veuillez laisser un commentaire expliquant pourquoi. Il a déjà été déclassé à plusieurs reprises, et finalement ypercube (merci) a expliqué au moins une raison. Je ne peux pas supprimer la réponse car elle est acceptée, alors autant aider à l'améliorer.]

Selon cet échange sur Microsoft, GETDATE() est passé d'être constant dans une requête à non déterministe dans SQL Server 2005. Rétrospectivement, je ne pense pas que ce soit exact. Je pense qu'il était complètement non déterministe avant SQL Server 2005, puis piraté dans quelque chose appelé "constante d'exécution non déterministe" depuis SQL Server 2005". La dernière phrase semble vraiment signifier "constante dans une requête".

(Et GETDATE() est défini comme sans ambiguïté et fièrement non déterministe, sans qualificatifs.)

Hélas, dans SQL Server, non déterministe ne signifie pas qu'une fonction est évaluée pour chaque ligne. SQL Server rend cela inutilement compliqué et ambigu avec très peu de documentation sur le sujet.

En pratique, l'appel de la fonction est évalué lorsque la requête est en cours d'exécution plutôt qu'une seule fois lorsque la requête est compilée et sa valeur change à chaque fois qu'elle est appelée. En pratique, GETDATE() n'est évalué qu'une seule fois pour chaque expression où il est utilisé -- au moment d'exécution plutôt que le temps de compilation . Cependant, Microsoft met rand() et getdate() dans une catégorie spéciale, appelée fonctions constantes d'exécution non déterministes. En revanche, Postgres ne saute pas à travers de tels cerceaux, il appelle simplement des fonctions qui ont une valeur constante lorsqu'elles sont exécutées comme "stables".

Malgré le commentaire de Martin Smith, la documentation de SQL Server n'est tout simplement pas explicite à ce sujet -- GETDATE() est décrit à la fois comme "non déterministe" et "constante d'exécution non déterministe", mais ce terme n'est pas vraiment expliqué. Le seul endroit où j'ai trouvé le terme , par exemple, les toutes prochaines lignes de la documentation disent de ne pas utiliser de fonctions non déterministes dans les sous-requêtes. Ce serait un conseil stupide pour une "constante d'exécution non déterministe".

Je suggérerais d'utiliser une variable avec une constante même dans une requête, de sorte que vous ayez une valeur cohérente. Cela rend également l'intention assez claire :vous voulez une seule valeur dans la requête. Dans une seule requête, vous pouvez faire quelque chose comme :

select . . . 
from (select getdate() as now) params cross join
     . . . 

En fait, c'est une suggestion qui devrait évaluer une seule fois dans la requête, mais il peut y avoir des exceptions. La confusion survient parce que getdate() renvoie la même valeur sur toutes les lignes différentes - mais il peut renvoyer des valeurs différentes dans différentes colonnes. Chaque expression avec getdate() est évalué indépendamment. Cela est évident si vous exécutez :

select rand(), rand()
from (values (1), (2), (3)) v(x);

Dans une procédure stockée, vous voudriez avoir une seule valeur dans une variable. Que se passe-t-il si la procédure stockée est exécutée alors que minuit passe et que la date change ? Quel impact cela a-t-il sur les résultats ?

En ce qui concerne les performances, je suppose que la recherche de date/heure est minimale et qu'une requête se produit une fois par expression lorsque la requête commence à s'exécuter. Cela ne devrait pas vraiment être un problème de performances, mais plutôt un problème de cohérence du code.