La déclaration de la volatilité des fonctions IMMUTABLE peut-elle nuire aux performances?

9

Les fonctions Postgres sont déclarées avec une classification de volatilité VOLATILE, STABLEouIMMUTABLE . Le projet est connu pour être très strict avec ces étiquettes pour les fonctions intégrées. Et pour cause. Exemple frappant: les index d'expression n'autorisent que les IMMUTABLEfonctions et celles-ci doivent être vraiment immuables pour éviter des résultats incorrects.

Les fonctions définies par l'utilisateur sont toujours libres d'être déclarées selon le choix du propriétaire. Le manuel conseille:

Pour de meilleurs résultats d'optimisation, vous devez étiqueter vos fonctions avec la catégorie de volatilité la plus stricte qui leur est valable.

... et ajoute une longue liste de choses qui peuvent mal tourner avec une étiquette de volatilité incorrecte.

Pourtant, il existe des cas où la simulation de l'immuabilité a un sens. Surtout quand vous savez que la fonction est, en fait, immuable dans votre portée. Exemple:

Toutes les implications possibles sur l'intégrité des données mises à part , quel est l'effet sur les performances? On pourrait supposer que déclarer une fonction IMMUTABLEne peut être que bénéfique pour les performances . Est-ce vrai?

La déclaration de la volatilité des fonctions peut-elle IMMUTABLE nuire aux performances?

Supposons que Postgres 10 actuel le réduise, mais toutes les versions récentes sont intéressantes.

Erwin Brandstetter
la source
1
Par ailleurs, le tout "vraiment immuable" sur les index d'expression est un vrai pita. C'est une horrible interface utilisateur. Nous devrions pouvoir les faire dans FORCEles deux cas. 100% des administrateurs de bases de données PostgreSQL expérimentés mentent pour contourner cette interface utilisateur avec des fonctions d'encapsulation. Au moins avec FORCE, nous n'aurions pas besoin de wrappers et nous n'aurions pas à mentir sur la volatilité fn déclarée.
Evan Carroll
1
Je suppose que FORCEc'est censé faire en sorte que les index d'expression acceptent des fonctions non immuables (tout en les marquant comme point de défaillance potentiel). Oui, cela semble être une solution plus élégante que les wrappers de fonctions immuables.
Erwin Brandstetter
Je ne sais presque rien de PostGres mais la volatilité n'est-elle pas redondante? Qu'est-ce que ça veut dire? Sérieusement, ne vous attendez pas à ce que ce soit fiable, parce que c'est fou ?
Anthony
@Anthony: J'ai clarifié un peu plus. Suivez le lien vers le manuel pour plus de détails.
Erwin Brandstetter

Réponses:

7

Oui, cela peut nuire aux performances.

Les fonctions SQL simples peuvent être "intégrées" dans la requête appelante. Citant le wiki Postgres :

Dans LANGUAGE SQLcertaines conditions, les fonctions SQL (c'est-à-dire ) verront leur corps de fonction intégré dans la requête appelante plutôt que d'être invoqué directement. Cela peut présenter des avantages substantiels en termes de performances, car le corps de la fonction est exposé au planificateur de la requête appelante, qui peut appliquer des optimisations telles que le pliage constant, le pushdown qual, etc.

Accentuation sur moi.

Pour imposer l'exactitude, il existe un certain nombre de conditions préalables. L'un d'eux :

si la fonction est déclarée IMMUTABLE, alors l'expression ne doit invoquer aucune fonction ou opérateur non immuable

Autrement dit, les fonctions SQL utilisant des fonctions non immuables mais toujours déclarées IMMTUTABLEsont exclues de cette optimisation. Déclenché par ces réponses connexes sur SO, j'ai effectué des tests approfondis:

Comparaison de base de ces deux variantes d'une fonction SQL simple (mappage des dates sur an integer, en ignorant l'année qui n'a pas d'importance à cet effet):

CREATE FUNCTION f_mmdd_tc_s(date) RETURNS int LANGUAGE sql STABLE    AS
$$SELECT to_char($1, 'MMDD')::int$$;

CREATE FUNCTION f_mmdd_tc_i(date) RETURNS int LANGUAGE sql IMMUTABLE AS
$$SELECT to_char($1, 'MMDD')::int$$;  -- cannot be inlined!

La fonction Postgres to_char()est seulement STABLE, pas IMMUTABLE(toutes les instances surchargées - pour des raisons qui dépassent le cadre de cette réponse ). Donc, le second est faux IMMUTABLEet s'avère 5 fois plus lent dans un test simple:

db <> violon ici

Cet exemple spécifique peut être remplacé par l'équivalent:

CREATE FUNCTION f_mmdd(date) RETURNS int LANGUAGE sql IMMUTABLE AS
$$SELECT (EXTRACT(month FROM $1) * 100 + EXTRACT(day FROM $1))::int$$;

Cela semblerait plus cher avec deux appels de fonction et plus de calculs. Mais l' IMMUTABLEétiquette est vrai (plus, la fonction utilisée est plus rapide et contraindre textà integerest plus cher aussi).

2x plus rapide que la variante la plus rapide ci-dessus (10x plus rapide que la plus lente). Le point étant: utilisez des IMMUTABLEfonctions lorsque cela est possible , vous n'avez pas à "tricher" pour commencer.

Erwin Brandstetter
la source
Des résultats sympas! Ayez un suivi immédiat: dba.stackexchange.com/q/212198/2639
Evan Carroll
Vous savez ce que je pense avoir manqué ici, que je ne savais pas. C'est STABLEégalement significatif. Je pensais que l'optimiseur ne IMMUTABLEfonctionnerait qu'en ligne .
Evan Carroll
VOLATILEtout aussi bien.
Erwin Brandstetter
Le wiki dit que la fonction est déclarée STABLE ou IMMUTABLE wiki.postgresql.org/wiki/Inlining_of_SQL_functions
Evan Carroll
.. sous "Conditions de ligne pour les fonctions de table ". Pas pour les fonctions scalaires. Je l'ai démontré dans le violon: dbfiddle.uk/…
Erwin Brandstetter