PostgreSQLLa base de données la plus sophistiquée au monde.
Documentation PostgreSQL 14.15 » Programmation serveur » Étendre SQL » Informations d'optimisation de fonction

38.11. Informations d'optimisation de fonction

Par défaut, une fonction est juste une « boîte noire » dont la base de données connait très peu le comportement. De ce fait, il peut arriver que les requêtes utilisant la fonction se trouvent exécutées beaucoup moins efficacement qu'elles ne pourraient. Il est possible de fournir une connaissance supplémentaire qui aide le planificateur à optimiser les appels de fonctions.

Quelques indications basiques peuvent être données via les annotations déclaratives présentes dans la commande CREATE FUNCTION. La plus importante de celles-ci est la catégorie de volatilité (IMMUTABLE, STABLE, ou VOLATILE) ; on doit toujours être très soucieux de la spécifier correctement lorsqu'on définit une fonction. La propriété de sûreté face au parallélisme (PARALLEL UNSAFE, PARALLEL RESTRICTED, ou PARALLEL SAFE) doit également être spécifiée pour espérer utiliser la fonction dans des requêtes parallélisées. Il peut aussi être utile de spécifier le coût estimé de l'exécution de la fonction, et le nombre de lignes qu'une fonction renvoyant un ensemble d'enregistrements est estimée renvoyer. Toutefois, la manière déclarative de spécifier ces deux informations ne permet seulement que de donner une valeur constante, ce qui est souvent inadéquat.

Il est aussi possible de rattacher une fonction de support de planification à une fonction appelable en SQL (appelée fonction cible), et ainsi de fournir sur la fonction cible une connaissance qui serait trop complexe à être représentée déclarativement. Les fonctions de support de planification doivent être écrites en C (alors que leurs fonctions cibles peuvent ne pas l'être), ce qui en fait une fonctionnalité avancée que relativement peu de personnes utiliseront.

Une fonction de support de planification doit avoir la signature SQL

supportfn(internal) returns internal
     

Elle est rattachée à sa fonction cible en spécifiant la clause SUPPORT dans la création de la fonction cible.

Les détails de l'API des fonctions de support de planification se trouvent dans le fichier src/include/nodes/supportnodes.h dans le code source de PostgreSQL. Ici, on ne fournit qu'une vue d'ensemble de ce que les fonctions de support de planification peuvent faire. L'ensemble des demandes possibles adressables à une fonction de support est extensible, si bien que d'autres choses seront possibles dans des versions ultérieures.

Certains appels de fonctions peuvent être simplifiés lors de la planification en se basant sur les propriétés spécifiques de la fonction. Par exemple, int4mul(n, 1) pourrait être simplifié par n. Ce type de transformation peut être exécuté par une fonction de support de planification, en lui faisant implémenter le type de demande SupportRequestSimplify. La fonction de support va être appelée pour chaque instance de la fonction cible trouvée dans l'arbre d'analyse de la requête. Si elle trouve qu'un appel particulier peut être simplifié en une autre forme, elle est capable de construire et renvoyer un arbre d'analyse représentant cette expression. Cela fonctionnera automatiquement pour les opérateurs basés sur cette fonction, également -- dans l'exemple juste ci-dessus, n * 1 serait aussi simplifié en n. (Mais notez que c'est juste un exemple ; cette optimisation particulière n'est pas réellement mise en oeuvre par PostgreSQL.) Nous ne garantissons pas que PostgreSQL n'appelera jamais la fonction cible dans les cas que la fonction de support pourrait simplifier. Assurez-vous d'une équivalence rigoureuse entre l'expression simplifiée et l'exécution réelle de la fonction cible.

Pour les fonctions cible qui renvoient un booléen, il est souvent utile d'estimer la fraction des lignes qui vont être sélectionnées par une clause WHERE utilisant cette fonction. Ceci est réalisable avec une fonction de support qui implémente le type de demande SupportRequestSelectivity.

Si le temps d'exécution d'une fonction cible est très dépendant de ses entrées, il peut être utile de fournir un coût d'exécution non constant pour celle-ci. Ceci est réalisable avec une fonction de support implémentant le type de demande SupportRequestCost.

Pour les fonctions cibles qui renvoient des ensembles de lignes, il est souvent utile de fournir une estimation non constante du nombre de lignes renvoyées. Ceci est réalisable avec une fonction de support implémentant le type de demande SupportRequestRows.

Pour les fonctions cibles qui renvoient un booléen, il est envisageable de convertir un appel de fonction au niveau d'un WHERE vers une ou plusieurs clauses d'un opérateur indexable. Ces clauses peuvent être exactement équivalentes à la condition de la fonction, ou bien elle peuvent être plus faibles (c'est-à-dire qu'elles peuvent accepter certaines valeurs que la condition via la fonction n'accepte pas). Dans ce dernier cas, la condition d'index est dite avec perte; elle peut toujours être utilisée pour un parcours d'index, mais la fonction devra être appelée pour chaque ligne renvoyée par l'index pour vérifier qu'elle satisfait la condition WHERE. Pour créer de telles conditions, la fonction de support doit implémenter le type de demande SupportRequestIndexCondition.