Comment des mots-clés immuables, stables et volatils influencent-ils le comportement de la fonction?

nous avons écrit une fonction get_timestamp() définie comme

CREATE OR REPLACE FUNCTION get_timestamp()
  RETURNS integer AS
$$
SELECT (FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 10) - 13885344000)::int;
$$
LANGUAGE SQL;

utilisé sur INSERT et UPDATE pour entrer ou modifier une valeur dans un champ créé et modifié dans l'enregistrement de la base de données. Cependant, nous avons constaté qu'en ajoutant ou en mettant à jour des enregistrements consécutivement, la même valeur était retournée.

sur l'inspection de la fonction dans pgAdmin III nous avons noté que sur l'exécution du SQL pour construire la fonction le mot clé immuable avait été injecté après le Énoncé de langage SQL. La documentation déclare que la valeur par défaut est VOLATILE (si aucune de ces valeurs n'apparaît, VOLATILE est l'hypothèse par défaut) donc je ne suis pas sûr de la raison pour laquelle immuable a été injecté, cependant, en changeant ce à STABLE a résolu la question des valeurs répétées.

NOTE: comme indiqué dans la réponse acceptée, immuable n'est jamais ajouté à une fonction par pgAdmin ou Postgres et doit avoir été ajouté pendant le développement.

je suppose que ce qui se passait était que cette fonction était évaluée et que le résultat était mis en cache pour l'optimisation, car il était marqué immuable indiquant au moteur Postgres que la valeur de retour ne devrait pas changer avec la même Liste de paramètres (vide). Cependant, lorsqu'elle n'est pas utilisée à l'intérieur d'un déclencheur, lorsqu'elle est utilisée directement dans le statement INSERT, la fonction retournerait une valeur distincte cinq fois avant de retourner la même valeur à partir de ce moment-là. Est-ce dû à un algorithme d'optimisation qui dit quelque chose comme "si une fonction immuable est utilisée plus de 5 fois dans une session, cache le résultat pour les appels futurs"?

toute clarification sur la façon dont ces mots-clés devraient être utilisés dans les fonctions de Postgres serait appréciée. Est STABLE l'option correcte pour nous Étant donné que nous utilisons cette fonction dans les triggers, ou y a-t-il autre chose à considérer, par exemple les docs disent:

(Il est inapproprié pour Après les déclencheurs qui souhaitent interroger les lignes modifié par la commande courante.)

mais je ne vois pas très bien pourquoi.

7
demandé sur NectarSoft 2015-02-17 22:20:21

1 réponses

le mot clé IMMUTABLE est jamais ajouté automatiquement par pgAdmin ou Postgres. Qui a jamais créé ou remplacé la fonction fait.

the correct function volatility (lire le manuel) le réglage pour la fonction donnée est VOLATILE , pas STABLE - ou il ne serait pas logique d'utiliser clock_timestamp() qui est VOLATILE par opposition à now() ou CURRENT_TIMESTAMP , qui sont définis STABLE : ceux renvoient le même horodatage dans la même transaction, par documentation :

clock_timestamp() renvoie l'heure actuelle réelle, et donc son la valeur change même à l'intérieur d'une seule commande SQL.

le manuel avertit que la fonction la volatilité STABLE ...

n'est pas approprié pour les déclencheurs AFTER qui souhaitent interroger des lignes modifiées par la commande en cours.

.. parce que l'évaluation répétée de la fonction de déclenchement pour la même rangée peut retourner différents résultats. Donc, pas STABLE . Je ne pense pas que l'avertissement est même nécessaire, car c'est assez évident.

et vous demandez:

avez-vous une idée de pourquoi la fonction est revenue correctement cinq temps avant de coller sur la cinquième valeur quand défini comme IMMUTABLE ?

citant le Postgres Wiki :

avec 9.2, le planificateur utilisera des plans spécifiques concernant paramètres envoyés (la requête sera planifiée à l'exécution), sauf si la requête est exécutée plusieurs fois et le planificateur décide que le plan Générique n'est pas trop cher que les plans spécifiques.

le Gras c'est moi qui souligne. Ne semble pas avoir de sens pour une fonction IMMUTABLE (ne fait pas de mal non plus), mais peut-être que l'utilisation d'une fonction VOLATILE à l'intérieur déclenche encore re-rabotage initial. (Le dernier bit est juste mon avis.)

Plus d'explications ici:

mis à part

trunc() est légèrement plus rapide que floor() et fait la même chose ici, puisque les nombres positifs sont garantis:

SELECT (trunc(EXTRACT(EPOCH FROM clock_timestamp()) * 10) - 13885344000)::int
6
répondu Erwin Brandstetter 2017-04-13 12:42:36