Performance de la fonction


46

Venant d’un arrière-plan MySQL, dans lequel les performances des procédures stockées (ancien article) et la facilité d’utilisation sont discutables, j’évalue PostgreSQL pour un nouveau produit destiné à mon entreprise.

L’une des choses que je voudrais faire est de déplacer une partie de la logique d’application dans les procédures stockées. C’est pourquoi je demande ici ce qu’il faut faire (bonnes pratiques) pour utiliser des fonctions dans PostgreSQL (9.0), en particulier en ce qui concerne les pièges de performance.


voulez-vous dire que vous ne voulez pas que les réponses mentionnent quelque chose qui ne soit pas lié à la performance?
Jack Douglas

Chris Travers blogue beaucoup sur les avantages de l’utilisation de procédures stockées, par exemple ici: ledgersmbdev.blogspot.de/2012/07/… et ici: ledgersmbdev.blogspot.de/2012/07/… parcourez son blog, il y a un beaucoup d'articles intéressants sur ce sujet.
a_horse_with_no_name

Réponses:


51

Strictement parlant, le terme "procédures stockées" désigne des procédures SQL dans Postgres, introduites avec Postgres 11. Lié:

Il y a aussi des fonctions qui font presque mais pas tout à fait la même chose et qui existent depuis le début.

Les fonctions avec ne LANGUAGE sqlsont fondamentalement que des fichiers de commandes avec des commandes SQL simples dans un wrapper de fonctions (et donc atomiques, toujours exécutées dans une transaction unique ) acceptant des paramètres. Toutes les instructions d'une fonction SQL sont planifiées en même temps , ce qui diffère légèrement de l'exécution d'une instruction après l'autre et peut affecter l'ordre dans lequel les verrous sont utilisés.

Pour n'importe quoi de plus, le langage le plus mature est PL / pgSQL ( LANGUAGE plpgsql). Cela fonctionne bien et a été amélioré avec chaque version au cours de la dernière décennie, mais cela sert surtout de colle pour les commandes SQL. Il n'est pas destiné aux calculs lourds (autres qu'avec des commandes SQL).

Les fonctions PL / pgSQL exécutent des requêtes telles que des instructions préparées . La réutilisation de plans de requête en cache permet de réduire les coûts liés à la planification et de les rendre un peu plus rapides que les instructions SQL équivalentes, ce qui peut avoir un effet notable en fonction des circonstances. Il peut également avoir des effets secondaires comme dans cette question connexe:

Ceci comporte les avantages et les inconvénients des déclarations préparées - comme indiqué dans le manuel . Pour les requêtes sur les tables avec la distribution des données irrégulières et des paramètres variables SQL dynamique avec EXECUTEpeut effectuer mieux lorsque le gain d'un plan d'exécution optimisé pour le paramètre donné (s) l' emporte sur le coût de la replanification.

Depuis Postgres 9.2, les plans d’exécution génériques sont toujours mis en cache pour la session mais, citant le manuel :

Cela se produit immédiatement pour les instructions préparées sans paramètres; sinon, cela se produit uniquement après que cinq exécutions ou plus ont généré des plans dont le coût moyen estimé (y compris les frais généraux de planification) est plus coûteux que l'estimation du coût générique du plan.

Nous obtenons le meilleur des deux mondes la plupart du temps (moins quelques frais généraux ajoutés) sans (ab) utiliser EXECUTE. Détails dans Nouveautés dans PostgreSQL 9.2 du wiki PostgreSQL .

Postgres 12 introduit la variable serveurplan_cache_mode supplémentaire pour forcer les plans génériques ou personnalisés. Pour les cas spéciaux, utilisez avec précaution.

Vous pouvez gagner gros avec des fonctions côté serveur qui empêchent des allers-retours supplémentaires vers le serveur de base de données à partir de votre application. Demandez au serveur d’exécuter autant que possible à la fois et ne renvoie qu’un résultat bien défini.

Évitez d'imbriquer des fonctions complexes, en particulier des fonctions de table ( RETURNING SETOF recordou TABLE (...)). Les fonctions sont des boîtes noires qui constituent des barrières d'optimisation pour le planificateur de requêtes. Elles sont optimisées séparément, pas dans le contexte de la requête externe, ce qui simplifie la planification, mais peut entraîner des plans moins que parfaits. En outre, le coût et la taille des résultats des fonctions ne peuvent pas être prédits de manière fiable.

Les exceptions à cette règle sont les simples fonctions SQL ( LANGUAGE sql), qui peuvent être "intégrées" - si certaines conditions préalables sont remplies . En savoir plus sur le fonctionnement du planificateur de requêtes dans cette présentation de Neil Conway (fonctions avancées).

Dans PostgreSQL, une fonction est automatiquement exécutée dans une seule transaction . Tout cela réussit ou rien. Si une exception se produit, tout est annulé. Mais il y a la gestion des erreurs ...

C'est aussi pour cette raison que les fonctions ne sont pas exactement des "procédures stockées" (même si ce terme est parfois utilisé, de manière trompeuse). Certaines commandes telles que VACUUM, CREATE INDEX CONCURRENTLYou CREATE DATABASEne peuvent pas être exécutées à l'intérieur d'un bloc de transaction, elles ne sont donc pas autorisées dans les fonctions. (Ni dans les procédures SQL, à ce jour, à partir de Postgres 11. Cela pourrait être ajouté plus tard.)

J'ai écrit des milliers de fonctions plpgsql au fil des ans.


2
@nhahtdh: "transaction automatique" n'est pas un terme technique. C’était juste une façon à peine élégante de dire… ce qu’on dit maintenant après ma clarification. Pas une transaction autonome du tout. "autonome" se trouve être un mot similaire.
Erwin Brandstetter

4
Vos réponses compilées ici et SO pourraient être un manuel épique de meilleures pratiques PostGreSQL.
Davos

10

Quelques DO:

  • Utilisez SQL comme langage de fonction lorsque cela est possible, car PG peut insérer les instructions en ligne.
  • Utilisez correctement IMMUTABLE / STABLE / VOLATILE, car PG peut mettre en cache les résultats s'il est immuable ou stable
  • Utilisez correctement STRICT, car PG peut simplement renvoyer null si l'une des entrées est nulle au lieu d'exécuter la fonction.
  • Pensez à PL / V8 lorsque vous ne pouvez pas utiliser SQL comme langage de fonction. Il est plus rapide que PL / pgSQL dans certains tests non scientifiques que j'ai exécutés
  • Utilisez LISTEN / NOTIFY pour les processus plus longs qui peuvent se produire en dehors de la transaction
  • Envisagez d'utiliser des fonctions pour implémenter la pagination car la pagination basée sur les clés peut être plus rapide que la pagination basée sur LIMIT
  • Assurez-vous de tester vos fonctions

C'est la première fois que je vois l'affirmation selon laquelle PL / V8 est plus rapide que PL / pgSQL. Avez-vous des chiffres (publiés) à l'appui de cela?
a_horse_with_no_name

@a_horse_with_no_name non, je ne le fais pas. Comme je l'ai dit, j'ai fait quelques tests non scientifiques. Ils étaient principalement logiques, pas d'accès aux données. Je vais essayer de faire des tests répétables sur Noël et de poster à nouveau ici.
Neil McGuigan

@a_horse_with_no_name Voici un exemple rapide et détaillé pour FizzBuzz plv8 vs plpgsql: blog.databasepatterns.com/2014/08/plv8-vs-plpgsql.html
Neil McGuigan

8

De manière générale, le fait de déplacer la logique d'application dans la base de données signifie que la procédure est plus rapide. Après tout, elle sera plus proche des données.

Je crois (mais je ne suis pas sûr à 100%) que les fonctions du langage SQL sont plus rapides que celles utilisant un autre langage car elles ne nécessitent pas de changement de contexte. L'inconvénient est qu'aucune logique procédurale n'est autorisée.

PL / pgSQL est le langage le plus mature et le plus complet des langages intégrés - mais pour la performance, le C peut être utilisé (bien que cela ne profite qu'aux fonctions gourmandes en ressources informatiques)


7

Vous pouvez faire des choses très intéressantes en utilisant des fonctions définies par l'utilisateur (UDF) dans postgresql. Par exemple, vous pouvez utiliser des dizaines de langues. Les systèmes intégrés pl / sql et pl / pgsql sont à la fois performants et fiables et utilisent une méthode de type bac à sable pour empêcher les utilisateurs de faire des choses trop terriblement dangereuses. Les fonctions UDF écrites en C vous offrent le summum en termes de puissance et de performances, car elles fonctionnent dans le même contexte que la base de données. Cependant, c'est comme si vous jouiez avec le feu, car même de petites erreurs peuvent causer d'énormes problèmes, avec le blocage du back-end ou la corruption des données. Les langages custome pl, tels que pl / R, pl / ruby, pl / perl, etc. vous offrent la possibilité d'écrire à la fois des couches de base de données et d'application dans les mêmes langues. Cela peut être pratique, car cela signifie que vous n'avez pas besoin d'apprendre à un programmeur perl java ou pl / pgsql, etc. à écrire un fichier UDF.

Enfin, il y a le langage pl / proxy . Ce langage UDF vous permet d’exécuter votre application sur des dizaines ou plus de serveurs postgresql d’arrière-plan à des fins de dimensionnement. Il a été développé par les gens de chez Skype et permet fondamentalement la solution de mise à l’échelle horizontale d’un homme pauvre. C'est étonnamment facile à écrire aussi.

Maintenant, en ce qui concerne le problème de performance. C'est une zone grise. Vous écrivez une application pour une personne? Ou pour 1000? ou pour 10 000 000? La manière dont vous construisez votre application et utilisez les fonctions définies par l'utilisateur dépendra BEAUCOUP de la façon dont vous essayez de faire évoluer votre système. Si vous écrivez pour des milliers et des milliers d'utilisateurs, la principale chose à faire est de réduire autant que possible la charge sur la base de données. Les fonctions utilisateur qui réduisent la quantité de données extraite et renvoyée dans la base de données contribueront à réduire la charge IO. Toutefois, s’ils commencent à augmenter la charge du processeur, ils risquent alors de poser problème. En règle générale, la priorité est de réduire la charge d'E / S. S'assurer ensuite que les FDU sont efficaces pour ne pas surcharger vos processeurs est la priorité suivante.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.