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.
postgresql
best-practices
plpgsql
Derek Downey
la source
la source
Réponses:
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 sql
sont 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
EXECUTE
peut 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 :
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 serveur
plan_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 record
ouTABLE (...)
). 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 CONCURRENTLY
ouCREATE DATABASE
ne 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.
la source
Quelques DO:
la source
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)
la source
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.
la source