33.6. Catégories de volatilité des fonctions
Chaque fonction a une classification de volatilité (volatility) comprenant VOLATILE, STABLE ou
IMMUTABLE. VOLATILE
est la valeur par défaut si la commande CREATE FUNCTION
ne spécifie pas de catégorie. La catégorie de volatilité est une
promesse à l'optimiseur sur le comportement de la fonction :
-
Une fonction VOLATILE peut tout faire,
y compris modifier la base de données. Elle peut renvoyer
différents résultats sur des appels successifs avec les mêmes
arguments. L'optimiseur ne fait aucune supposition sur le
comportement de telles fonctions. Une requête utilisant une
fonction volatile ré-évaluera la fonction à chaque ligne où sa
valeur est nécessaire.
-
Une fonction STABLE ne peut pas
modifier la base de données et est garantie de renvoyer les
mêmes résultats si elle est appelée avec les mêmes arguments
pour toutes les lignes à l'intérieur d'une même instruction.
Cette catégorie permet à l'optimiseur d'optimiser plusieurs
appels de la fonction dans une seule requête. En particulier,
vous pouvez utiliser en toute sécurité une expression contenant
une telle fonction dans une condition de parcours d'index (car
un parcours d'index évaluera la valeur de la comparaison une
seule fois, pas une fois pour chaque ligne, utiliser une
fonction VOLATILE dans une condition
de parcours d'index n'est pas valide).
-
Une fonction IMMUTABLE ne peut pas
modifier la base de données et est garantie de toujours
renvoyer les mêmes résultats si elle est appelée avec les mêmes
arguments. Cette catégorie permet à l'optimiseur de pré-évaluer
la fonction quand une requête l'appelle avec des arguments
constants. Par exemple, une requête comme SELECT ... WHERE x = 2 + 2 peut être simplifiée
pour obtenir SELECT ... WHERE x = 4
car la fonction sous-jacente de l'opérateur d'addition est
indiquée IMMUTABLE.
Pour une meilleure optimisation des résultats, vous devez mettre un
label sur les fonctions avec la catégorie la plus volatile valide
pour elles.
Toute fonction avec des effets de bord
doit
être indiquée comme VOLATILE, de façon à ce que les appels ne puissent pas
être optimisés. Même une fonction sans effets de bord doit être
indiquée comme VOLATILE si sa valeur peut
changer à l'intérieur d'une seule requête ; quelques exemples sont
random(), currval(), timeofday().
Il y a relativement peu de différences entre les catégories
STABLE et IMMUTABLE
en considérant les requêtes interactives qui sont planifiées et
immédiatement exécutées : il importe peu que la fonction soit
exécutée une fois lors de la planification ou une fois au lancement
de l'exécution de la requête mais cela fait une grosse différence si
le plan est sauvegardé et utilisé plus tard. Placer un label
IMMUTABLE sur une fonction quand elle ne
l'est pas vraiment pourrait avoir comme conséquence de la considérer
prématurément comme une constante lors de la planification et
résulterait en une valeur erronée lors d'une utilisation ultérieure
de ce plan d'exécution. C'est un danger qui arrive lors de
l'utilisattion d'instructions préparées ou avec l'utilisation de
langages de fonctions mettant les plans d'exécutions en cache (comme
PL/pgSQL).
À cause du comportement à base d'images de MVCC (voir le Chapitre 12,
Contrôle d'accès simultané), une fonction contenant seulement des
commandes
SELECT
peut
être indiquée STABLE en toute sécurité même
s'il sélectionne des données à partir de tables qui pourraient avoir
subi des modifications entre temps par des requêtes concurrentes.
PostgreSQL™ exécutera une
fonction STABLE en utilisant l'image établie
par la requête appelante et n'aura qu'une vision figée de la base de
données au cours de la requête. Notez aussi que la famille de
fonctions current_timestamp est qualifiée
de stable car leurs valeurs ne changent pas dans une transaction.
Ce même comportement d'images est utilisé pour les commandes
SELECT
à l'intérieur de
fonctions IMMUTABLE. Il est généralement
déconseillé de sélectionner des tables de la base de données à
l'intérieur de fonctions IMMUTABLE car
l'immutabilité sera rompue si le contenu de la table change.
Néanmoins, PostgreSQL™ ne vous
force pas à ne pas le faire.
Une erreur commune est de placer un label sur une fonction IMMUTABLE quand son résultat dépend d'un paramètre de
configuration. Par exemple, une fonction qui manipule des types
date/heure pourrait bien avoir des résultats dépendant du paramètre
timezone. Pour être
sécurisées, de telles fonctions devraient avoir le label STABLE à la place.
Note
Avant PostgreSQL™ version
8.0, le prérequis que les fonctions STABLE et IMMUTABLE ne
pouvaient pas modifier la base de données n'était pas contraint
par le système. La version 8.0 le contraint en réclamant que les
fonctions SQL et les fonctions de langages de procédures de ces
catégories ne contiennent pas de commandes SQL autre que
SELECT
(ceci n'a
pas été complètement testé car de telles fonctions pourraient
toujours appeler des fonctions VOLATILE
qui modifient la base de données. Si vous le faites, vous
trouverez que la fonction STABLE ou
IMMUTABLE n'est pas au courant des
modifications effectuées sur la base de données par la fonction
appelée).