web-dev-qa-db-fra.com

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

Par meilleur, je veux dire, est-ce que cela améliore les performances d’un montant non marginal?

Autrement dit, chaque fois que j'appelle GETDATE(), quelle quantité de work le serveur fait-il pour renvoyer cette valeur?

Si j'utilise GETDATE() à plusieurs endroits d'une procédure stockée, devrais-je plutôt créer une variable pour stocker la date de la transaction?

declare @transDate datetime = GETDATE()

Les données de référence seraient fantastiques. 

EDITJe tiens à préciser: je m'intéresse principalement aux différences de performances réelles entre ces deux possibilités et à leur importance ou non. 

32
Shmiddty

[NOTE: Si vous envisagez de réduire cette réponse, veuillez laisser un commentaire expliquant pourquoi. Il a déjà été voté plusieurs fois, et finalement ypercube (merci) a expliqué au moins une des raisons. Je ne peux pas supprimer la réponse car elle est acceptée, vous pouvez donc aussi bien l’aider à l’améliorer.]

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

(Et GETDATE() est défini comme non équivoque et fièrement non déterministe, sans qualificatif.)

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

En pratique, l'appel de fonction est évalué lorsque la requête est en cours d'exécution plutôt qu'une fois lorsque la requête est compilée et que sa valeur change à chaque appel. En pratique, GETDATE() n'est évalué qu'une fois pour chaque expression où il est utilisé - à heure d'exécution plutôt que temps de compilation. Cependant, Microsoft place Rand() et getdate() dans une catégorie spéciale, appelée fonction constante non déterministe. En revanche, Postgres ne saute pas à travers de tels obstacles, il appelle simplement les fonctions qui ont une valeur constante lorsqu’elles sont exécutées en tant que "stables".

En dépit du 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 indiquent de ne pas utiliser de fonctions non déterministes dans les sous-requêtes. Ce serait un conseil idiot 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 clarifie également l’intention: Vous voulez une valeur unique 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, il s'agit d'une suggestion selon laquelle devrait n'évaluer qu'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 des colonnes différentes. Chaque expression avec getdate() est évaluée indépendamment. Ceci 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 valeur unique dans une variable. Que se passe-t-il si la procédure stockée est exécutée lorsque passe minuit 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 est exécutée une fois par expression au début de l’exécution de la requête. Cela ne devrait pas vraiment être un problème de performances, mais plutôt un problème de cohérence du code.

20
Gordon Linoff

Ma suggestion serait d'utiliser une variable principalement parce que si vous avez un processus long, la valeur GetDate() peut être différente d'un appel à l'autre. 

À moins que vous n'utilisiez que la partie Date de GetDate(), vous serez sûr de toujours utiliser la même valeur.

17
Taryn

J'essayais sur quelques procédures stockées en utilisant la fonction GETDATE () comme variable dans un SP et j'avais une augmentation du nombre de lectures IO et du temps d'exécution, du fait que l'optimiseur de requêtes ne sait pas quelle est la valeur à exploiter read this Exécution de procédures stockées avec paramètres, variables et littéraux , avec ceci dit, vous pouvez utiliser la fonction GETDATE () dans chaque partie du SP comme @Gordon Linoff a mentionné son la valeur ne change pas pendant l'exécution ou afin d'éviter/supprimer l'idée que la valeur pourrait changer, j'ai créé un paramètre de cette façon:

CREATE PROC TestGetdate
(
@CurrentDate DATETIME = NULL
)
AS
SET CurrentDate  = GETDATE()

......__ puis utilisez les paramètres comme bon vous semble, vous obtiendrez de bons résultats

Tous les commentaires ou suggestions sont les bienvenus.

1
jthalliens

Une raison d'utiliser une variable avec getdate () ou des fonctions telles que suser_sname () est une énorme différence de performances si vous insérez des lignes ou si vous utilisez GROUP BY. Vous remarquerez ceci si vous insérez un grand nombre de lignes.

J'ai moi-même souffert de cette migration de 300 Go de données vers plusieurs tables.

1
MarianoC

J'ai utilisé

WHERE ActualDateShipped+30 > dbo.Today()

en combinaison avec la fonction ci-dessous. Apporté mon temps de requête de 13 secondes à 2 secondes. Aucune réponse antérieure dans cet article n'a aidé ce problème dans SQL 2008/R2.

CREATE FUNCTION [dbo].[Today]()

    RETURNS date
    AS
    BEGIN

        DECLARE @today date = getdate()

        RETURN @today
    End
0
pghcpa