Connexions distantes Module V2 22.01 - Public Documents about PostgreSQL ...
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
Module V2 Connexions distantes 22.01
Dalibo SCOP https://dalibo.com/formations Connexions distantes Module V2
TITRE : Connexions distantes SOUS-TITRE : Module V2 REVISION: 22.01 DATE: 15 janvier 2022 COPYRIGHT: © 2005-2022 DALIBO SARL SCOP LICENCE: Creative Commons BY-NC-SA Postgres®, PostgreSQL® and the Slonik Logo are trademarks or registered trademarks of the PostgreSQL Community Association of Canada, and used with their permission. (Les noms PostgreSQL® et Postgres®, et le logo Slonik sont des marques déposées par PostgreSQL Community Association of Canada. Voir https://www.postgresql.org/about/policies/trademarks/ ) Remerciements : Ce manuel de formation est une aventure collective qui se transmet au sein de notre société depuis des années. Nous remercions chaleureusement ici toutes les personnes qui ont contribué directement ou indirectement à cet ouvrage, notam- ment : Jean-Paul Argudo, Alexandre Anriot, Carole Arnaud, Alexandre Baron, David Bidoc, Sharon Bonan, Franck Boudehen, Arnaud Bruniquel, Damien Clochard, Christophe Cour- tois, Marc Cousin, Gilles Darold, Jehan-Guillaume de Rorthais, Ronan Dunklau, Vik Fear- ing, Stefan Fercot, Pierre Giraud, Nicolas Gollet, Dimitri Fontaine, Florent Jardin, Vir- ginie Jourdan, Luc Lamarle, Denis Laxalde, Guillaume Lelarge, Benoit Lobréau, Jean-Louis Louër, Thibaut Madelaine, Adrien Nayrat, Alexandre Pereira, Flavie Perette, Robin Por- tigliatti, Thomas Reiss, Maël Rimbault, Julien Rouhaud, Stéphane Schildknecht, Julien Tachoires, Nicolas Thauvin, Be Hai Tran, Christophe Truffier, Cédric Villemain, Thibaud Walkowiak, Frédéric Yhuel. À propos de DALIBO : DALIBO est le spécialiste français de PostgreSQL. Nous proposons du support, de la formation et du conseil depuis 2005. Retrouvez toutes nos formations sur https://dalibo.com/formations
LICENCE CREATIVE COMMONS BY-NC-SA 2.0 FR Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions Vous êtes autorisé à : • Partager, copier, distribuer et communiquer le matériel par tous moyens et sous tous formats • Adapter, remixer, transformer et créer à partir du matériel Dalibo ne peut retirer les autorisations concédées par la licence tant que vous appliquez les termes de cette licence selon les conditions suivantes : Attribution : Vous devez créditer l’œuvre, intégrer un lien vers la licence et indiquer si des modifications ont été effectuées à l’œuvre. Vous devez indiquer ces informations par tous les moyens raisonnables, sans toutefois suggérer que Dalibo vous soutient ou soutient la façon dont vous avez utilisé ce document. Pas d’Utilisation Commerciale : Vous n’êtes pas autorisé à faire un usage commercial de ce document, tout ou partie du matériel le composant. Partage dans les Mêmes Conditions : Dans le cas où vous effectuez un remix, que vous transformez, ou créez à partir du matériel composant le document original, vous devez diffuser le document modifié dans les même conditions, c’est à dire avec la même licence avec laquelle le document original a été diffusé. Pas de restrictions complémentaires : Vous n’êtes pas autorisé à appliquer des conditions légales ou des mesures techniques qui restreindraient légalement autrui à utiliser le doc- ument dans les conditions décrites par la licence. Note : Ceci est un résumé de la licence. Le texte complet est disponible ici : https://creativecommons.org/licenses/by-nc-sa/2.0/fr/legalcode Pour toute demande au sujet des conditions d’utilisation de ce document, envoyez vos questions à contact@dalibo.com1 ! 1 mailto:contact@dalibo.com
Chers lectrices & lecteurs, Nos formations PostgreSQL sont issues de nombreuses années d’études, d’expérience de terrain et de passion pour les logiciels libres. Pour Dalibo, l’utilisation de PostgreSQL n’est pas une marque d’opportunisme commercial, mais l’expression d’un engagement de longue date. Le choix de l’Open Source est aussi le choix de l’implication dans la commu- nauté du logiciel. Au-delà du contenu technique en lui-même, notre intention est de transmettre les valeurs qui animent et unissent les développeurs de PostgreSQL depuis toujours : partage, ou- verture, transparence, créativité, dynamisme... Le but premier de nos formations est de vous aider à mieux exploiter toute la puissance de PostgreSQL mais nous espérons égale- ment qu’elles vous inciteront à devenir un membre actif de la communauté en partageant à votre tour le savoir-faire que vous aurez acquis avec nous. Nous mettons un point d’honneur à maintenir nos manuels à jour, avec des informations précises et des exemples détaillés. Toutefois malgré nos efforts et nos multiples relec- tures, il est probable que ce document contienne des oublis, des coquilles, des impréci- sions ou des erreurs. Si vous constatez un souci, n’hésitez pas à le signaler via l’adresse formation@dalibo.com !
Table des Matières Licence Creative Commons BY-NC-SA 2.0 FR 5 1 Connexions distantes 10 1.1 Accès à distance à d’autres sources de données . . . . . . . . . . . . . 10 1.2 SQL/MED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.3 dblink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 1.4 PL/Proxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 1.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 1.6 Travaux pratiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 1.7 Travaux pratiques (solutions) . . . . . . . . . . . . . . . . . . . . . . . . 32 9
Connexions distantes 1 CONNEXIONS DISTANTES 1.1 ACCÈS À DISTANCE À D'AUTRES SOURCES DE DONNÉES • Modules historiques : dblink • SQL/MED & Foreign Data Wrappers • Sharding par fonctions : PL/Proxy • Le sharding est Work In Progress Nativement, lorsqu’un utilisateur est connecté à une base de données PostgreSQL, sa vision du monde est contenue hermétiquement dans cette base. Il n’a pas accès aux objets des autres bases de la même instance ou d’une autre instance. Cependant, il existe principalement 3 méthodes pour accéder à des données externes à la base sous PostgreSQL. La norme SQL/MED est la méthode recommandée pour accéder à des objets distants. Elle permet l’accès à de nombreuses sources de données différentes grâce l’utilisation de connecteurs appelés Foreign Data Wrappers. Historiquement, les utilisateurs de PostgreSQL passaient par l’extension dblink, qui per- met l’accès à des données externes. Cependant, cet accès ne concerne que des serveurs PostgreSQL. De plus, son utilisation prête facilement à accès moins performant et moins sécurisés que la norme SQL/MED. PL/Proxy est un cas d’utilisation très différent : cette extension, au départ développée par Skype, permet de distribuer des appels de fonctions PL sur plusieurs nœuds. Le sharding n’est pas intégré de manière simple à PostgreSQL dans sa version commu- nautaire. Il est déjà possible d’en faire une version primitive avec des partitions basées sur des tables distantes (donc avec SQL/MED), mais nous n’en sommes qu’au début. Des éditeurs proposent des extensions, propriétaires ou expérimentales, ou des forks de Post- greSQL dédiés. Comme souvent, il faut se poser la question du besoin réel par rapport à une instance PostgreSQL bien optimisée avant d’utiliser des outils qui vont ajouter une couche supplémentaire de complexité dans votre infrastructure. 10
1. CONNEXIONS DISTANTES 1.2 SQL/MED • Management of External Data • Extension de la norme SQL ISO • Données externes présentées comme des tables • Grand nombre de fonctionnalités disponibles – mais tous les connecteurs n’implémentent pas tout • Données accessibles par l’intermédiaire de tables – ces tables ne contiennent pas les données localement – l’accès à ces tables provoque une récupération des données distantes SQL/MED est un des tomes de la norme SQL, traitant de l’accès aux données externes (Management of External Data). Elle fournit donc un certain nombre d’éléments conceptuels, et de syntaxe, permettant la déclaration d’accès à des données externes. Ces données externes sont bien sûr présen- tées comme des tables. PostgreSQL suit cette norme et est ainsi capable de requêter des tables distantes à travers des pilotes (appelés Foreign Data Wrapper). Les seuls connecteurs livrés par défaut sont file_fdw (pour lire des fichiers plats de type CSV accessibles du serveur PostgreSQL) et postgres_fdw (qui permet de se connecter à un autre serveur PostgreSQL. 1.2.1 OBJETS PROPOSÉS PAR SQL/MED • Foreign Data Wrapper – connecteur permettant la connexion à un serveur externe et l’exécution de requête • Foreign Server – serveur distant • User Mapping – correspondance d’utilisateur local vers distant • Foreign Table – table distante (ou table externe) La norme SQL/MED définit quatre types d’objets. Le Foreign Data Wrapper est le connecteur permettant la connexion à un serveur distant, l’exécution de requêtes sur ce serveur, et la récupération des résultats par l’intermédiaire d’une table distante. 11 https://dalibo.com/formations
Connexions distantes Le Foreign Server est la définition d’un serveur distant. Il est lié à un Foreign Data Wrapper lors de sa création, des options sont disponibles pour indiquer le fichier ou l’adresse IP et le port, ainsi que d’autres informations d’importance pour le connecteur. Un User Mapping permet de définir qui localement a le droit de se connecter sur un serveur distant en tant que tel utilisateur sur le serveur distant. La définition d’un User Mapping est optionnel. Une Foreign Table contient la définition de la table distante : nom des colonnes, et type. Elle est liée à un Foreign Server. 1.2.2 FOREIGN DATA WRAPPER • Pilote d’accès aux données • Couverture variable des fonctionnalités • Qualité variable • Exemples de connecteurs – PostgreSQL, SQLite, Oracle, MySQL (lecture/écriture) – fichier CSV, fichier fixe (en lecture) – ODBC, JDBC, Multicorn – CouchDB, Redis (NoSQL) • Disponible généralement sous la forme d’une extension – ajouter l’extension ajoute le Foreign Data Wrapper à une base Les trois Foreign Data Wrappers les plus aboutis sont sans conteste ceux pour PostgreSQL (disponible en module contrib), Oracle et SQLite. Ces trois pilotes supportent un grand nombre de fonctionnalités (si ce n’est pas toutes) de l’implémentation SQL/MED par Post- greSQL. De nombreux pilotes spécialisés existent, entre autres pour accéder à des bases NoSQL comme MongDB, CouchDB ou Redis, ou à des fichiers. Il existe aussi des drivers génériques : • ODBC : utilisation de driver ODBC • JDBC : utilisation de driver JDBC • Multicorn : accès aux données au travers d’une API Python, permettant donc d’écrire facilement un accès pour un nouveau type de service. 12
1. CONNEXIONS DISTANTES La liste complète des Foreign Data Wrappers disponibles pour PostgreSQL peut être con- sultée sur le wiki de postgresql.org2 . Encore une fois, leur couverture des fonctionnalités disponibles est très variable ainsi que leur qualité. Il convient de rester prudent et de bien tester ces extensions. Par exemple, pour ajouter le Foreign Data Wrapper pour PostgreSQL, on procédera ainsi : CREATE EXTENSION postgres_fdw; La création cette extension dans une base provoquera l’ajout du Foreign Data Wrapper : b1=# CREATE EXTENSION postgres_fdw; CREATE EXTENSION b1=# \dx+ postgres_fdw Objects in extension "postgres_fdw" Object descriptiong --------------------------------------------- foreign-data wrapper postgres_fdw function postgres_fdw_disconnect(text) function postgres_fdw_disconnect_all() function postgres_fdw_get_connections() function postgres_fdw_handler() function postgres_fdw_validator(text[],oid) (6 rows) b1=# \dew List of foreign-data wrappers Name | Owner | Handler | Validatorg --------------+----------+----------------------+------------------------ postgres_fdw | postgres | postgres_fdw_handler | postgres_fdw_validator (1 row) 1.2.3 FONCTIONNALITÉS DISPONIBLES POUR UN FDW • Support des lecture de tables (SELECT) • Support des écriture de tables (y compris TRUNCATE) – directement pour INSERT – récupération de la ligne en local pour un UPDATE/DELETE • Envoi sur le serveur distant – des prédicats – des jointures si les deux tables jointes font partie du même serveur distant 2 https://wiki.postgresql.org/wiki/Foreign_data_wrappers 13 https://dalibo.com/formations
Connexions distantes – des agrégations • Mais aussi – support du EXPLAIN – support du ANALYZE – support de la parallélisation – support des exécutions asynchrones (v14) – possibilité d’importer un schéma complet L’implémentation SQL/MED permet l’ajout de ces fonctionnalités dans un Foreign Data Wrapper. Cependant, une majorité de ces fonctionnalités est optionnelle. Seule la lecture des données est obligatoire. Les chapitres suivant montrent des exemples de ces fonctionnalités sur deux Foreign Data Wrappers. 1.2.4 FOREIGN SERVER • Encapsule les informations de connexion • Le Foreign Data Wrapper utilise ces informations pour la connexion • Chaque Foreign Data Wrapper propose des options spécifiques – nom du fichier pour un FDW listant des fichiers – adresse IP, port, nom de base pour un serveur SQL – autres Pour accéder aux données d’un autre serveur, il faut pouvoir s’y connecter. Le Foreign Server regroupe les informations permettant cette connexion : par exemple adresse IP et port. Voici un exemple d’ajout de serveur distant : CREATE SERVER serveur2 FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '192.168.122.1', port '5432', dbname 'b1') ; 14
1. CONNEXIONS DISTANTES 1.2.5 USER MAPPING • Correspondance utilisateur local / utilisateur distant • Mot de passe stocké chiffré • Optionnel – aucun intérêt pour les FDW fichiers – essentiel pour les FDW de bases de données Définir un User Mapping permet d’indiquer au Foreign Data Wrapper quel utilisateur utilisé pour la connexion au serveur distant. Par exemple, avec cette définition : CREATE USER MAPPING FOR bob SERVER serveur2 OPTIONS (user 'alice', password 'secret'); Si l’utilisateur bob local accède à une table distante dépendant du serveur distant serveur2, la connexion au serveur distant passera par l’utilisateur alice sur le serveur distant. 1.2.6 FOREIGN TABLE • Définit une table distante • Doit comporter les colonnes du bon type – pas forcément toutes – pas forcément dans le même ordre • Peut être une partition d’une table partitionnée • Possibilité d’importer un schéma complet – simplifie grandement la création des tables distantes Voici un premier exemple pour une table simple : CREATE FOREIGN TABLE films ( code char(5) NOT NULL, titre varchar(40) NOT NULL, did integer NOT NULL, date_prod date, type varchar(10), duree interval hour to minute ) SERVER serveur2 ; Lors de l’accès (avec un SELECT par exemple) à la table films, PostgreSQL va chercher la définition du serveur serveur2, ce qui lui permettra de connaître le Foreign Data Wrapper 15 https://dalibo.com/formations
Connexions distantes responsable de la récupération des données et donnera la main à ce connecteur. Et voici un second exemple, cette fois pour une partition : CREATE FOREIGN TABLE stock202112 PARTITION OF stock FOR VALUES FROM ('2021-12-01') TO ('2022-01-01') SERVER serveur2; Dans ce cas, l’accès à la table partitionnée locale stock accédera à des données locales (les autres partitions) mais aussi à des données distantes avec au moins la partition stock202112. Cette étape de création des tables distantes est fastidieuse et peut amener des problèmes si on se trompe sur le nom des colonnes ou sur leur type. C’est d’autant plus vrai que le nombre de tables à créer est important. Dans ce cas, elle peut être avantageusement remplacée par un appel à l’ordre IMPORT FOREIGN SCHEMA. Disponible à partir de la version 9.5, il permet l’import d’un schéma complet. 1.2.7 EXEMPLE : FILE_FDW Foreign Data Wrapper de lecture de fichiers CSV. CREATE EXTENSION file_fdw; CREATE SERVER fichier FOREIGN DATA WRAPPER file_fdw ; CREATE FOREIGN TABLE donnees_statistiques (f1 numeric, f2 numeric) SERVER fichier OPTIONS (filename '/tmp/fichier_donnees_statistiques.csv', format 'csv', delimiter ';') ; Quel que soit le connecteur, la création d’un accès se fait en 3 étapes minimum : • Installation du connecteur : aucun Foreign Data Wrapper n’est présent par défaut. Il se peut que vous ayez d’abord à l’installer sur le serveur au niveau du système d’exploitation. • Création du serveur : permet de spécifier un certain nombre d’informations génériques à un serveur distant, qu’on n’aura pas à repréciser pour chaque objet de ce serveur. • Création de la table distante : l’objet qu’on souhaite rendre visible. Éventuellement, on peut vouloir créer un User Mapping, mais ce n’est pas nécessaire pour le FDW file_fdw. 16
1. CONNEXIONS DISTANTES En reprenant l’exemple ci-dessus et avec un fichier /tmp/fichier_donnees_statistiques.csv contenant les lignes suivantes : 1;1.2 2;2.4 3;0 4;5.6 Voici ce que donnerait quelques opérations sur cette table distante : SELECT * FROM donnees_statistiques; f1 | f2g ----+----- 1 | 1.2 2 | 2.4 3 | 0 4 | 5.6 (4 rows) SELECT * FROM donnees_statistiques WHERE f1=2; f1 | f2g ----+----- 2 | 2.4 (1 row) EXPLAIN SELECT * FROM donnees_statistiques WHERE f1=2; QUERY PLAN ------------------------------------------------------------------------- Foreign Scan on donnees_statistiques (cost=0.00..1.10 rows=1 width=64) Filter: (f1 = '2'::numeric) Foreign File: /tmp/fichier_donnees_statistiques.csv Foreign File Size: 25 b (4 rows) postgres=# insert into donnees_statistiques values (5,100.23); ERROR: cannot insert into foreign table "donnees_statistiques" 17 https://dalibo.com/formations
Connexions distantes 1.2.8 EXEMPLE : POSTGRES_FDW • Pilote le plus abouti, et pour cause – il permet de tester les nouvelles fonctionnalités de SQL/MED – il sert d’exemple pour les autres FDW • Propose en plus : – une gestion des transactions explicites – un pooler de connexions Nous créons une table sur un serveur distant. Par simplicité, nous utiliserons le même serveur mais une base différente. Créons cette base et cette table : dalibo=# CREATE DATABASE distante; CREATE DATABASE dalibo=# \c distante You are now connected to database "distante" as user "dalibo". distante=# CREATE TABLE personnes (id integer, nom text); CREATE TABLE distante=# INSERT INTO personnes (id, nom) VALUES (1, 'alice'), (2, 'bertrand'), (3, 'charlotte'), (4, 'david'); INSERT 0 4 distante=# ANALYZE personnes; ANALYZE Maintenant nous pouvons revenir à notre base d’origine et mettre en place la relation avec le « serveur distant » : distante=# \c dalibo You are now connected to database "dalibo" as user "dalibo". dalibo=# CREATE EXTENSION postgres_fdw; CREATE EXTENSION dalibo=# CREATE SERVER serveur_distant FOREIGN DATA WRAPPER postgres_fdw OPTIONS (HOST 'localhost',PORT '5432', DBNAME 'distante'); CREATE SERVER dalibo=# CREATE USER MAPPING FOR dalibo SERVER serveur_distant OPTIONS (user 'dalibo', password 'mon_mdp'); CREATE USER MAPPING dalibo=# CREATE FOREIGN TABLE personnes (id integer, nom text) 18
1. CONNEXIONS DISTANTES SERVER serveur_distant; CREATE FOREIGN TABLE Et c’est tout ! Nous pouvons désormais utiliser la table distante personnes comme si elle était une table locale de notre base. SELECT * FROM personnes; id | nom ----+----------- 1 | alice 2 | bertrand 3 | charlotte 4 | david EXPLAIN (ANALYZE, VERBOSE) SELECT * FROM personnes; QUERY PLAN ---------------------------------------------------------------------------- Foreign Scan on public.personnes (cost=100.00..150.95 rows=1365 width=36) (actual time=0.655..0.657 rows=4 loops=1) Output: id, nom Remote SQL: SELECT id, nom FROM public.personnes Total runtime: 1.197 ms En plus, si nous filtrons notre requête, le filtre est exécuté sur le serveur distant, réduisant considérablement le trafic réseau et le traitement associé. dalibo=# EXPLAIN (ANALYZE, VERBOSE) SELECT * FROM personnes WHERE id = 3; QUERY PLAN ---------------------------------------------------------------------------- Foreign Scan on public.personnes (cost=100.00..127.20 rows=7 width=36) (actual time=1.778..1.779 rows=1 loops=1) Output: id, nom Remote SQL: SELECT id, nom FROM public.personnes WHERE ((id = 3)) Total runtime: 2.240 ms Noter qu’EXPLAIN exige l’option VERBOSE pour afficher le code envoyé à l’instance distante. Il est possible d’écrire vers ces tables aussi, à condition que le connecteur FDW le perme- tte. En utilisant l’exemple de la section précédente, on note qu’il y a un aller-retour entre la sélection des lignes à modifier (ou supprimer) et la modification (suppression) de ces lignes : EXPLAIN (ANALYZE, VERBOSE) UPDATE personnes SET nom = 'agathe' WHERE id = 1 ; 19 https://dalibo.com/formations
Connexions distantes QUERY PLAN ------------------------------------------------------------------------------- Update on public.personnes (cost=100.00..140.35 rows=12 width=10) (actual time=2.086..2.086 rows=0 loops=1) Remote SQL: UPDATE public.personnes SET nom = $2 WHERE ctid = $1 -> Foreign Scan on public.personnes (cost=100.00..140.35 rows=12 width=10) (actual time=1.040..1.042 rows=1 loops=1) Output: id, 'agathe'::text, ctid Remote SQL: SELECT id, ctid FROM public.personnes WHERE ((id = 1)) FOR UPDATE Total runtime: 2.660 ms SELECT * FROM personnes; id | nom ----+----------- 2 | bertrand 3 | charlotte 4 | david 1 | agathe On peut aussi constater que l’écriture distante respecte les transactions : dalibo=# BEGIN; BEGIN dalibo=# DELETE FROM personnes WHERE id=2; DELETE 1 dalibo=# SELECT * FROM personnes; id | nom ----+----------- 3 | charlotte 4 | david 1 | agathe (3 rows) dalibo=# ROLLBACK; ROLLBACK dalibo=# SELECT * FROM personnes; id | nom ----+----------- 2 | bertrand 3 | charlotte 4 | david 1 | agathe (4 rows) 20
1. CONNEXIONS DISTANTES Attention à ne pas perdre de vue qu’une table distante n’est pas une table locale. L’accès à ses données est plus lent, surtout quand on souhaite récupérer de manière répétitive peu d’enregistrements : on a systématiquement une latence réseau, éventuellement une analyse de la requête envoyée au serveur distant, etc. Les jointures ne sont pas « poussées » au serveur distant avant PostgreSQL 9.6 et pour des bases PostgreSQL. Un accès par Nested Loop (boucle imbriquée entre les deux tables) est habituellement inenvisageable entre deux tables distantes : la boucle interne (celle qui en local serait un accès à une table par index) entraînerait une requête individuelle par itération, ce qui serait horriblement peu performant. Comme avec tout FDW, il existe des restrictions. Par exemple, avec postgres_fdw, un TRUNCATE d’une table distante n’est pas possible avant PostgreSQL 14. Les tables distantes sont donc à réserver à des accès intermittents. Il ne faut pas les utiliser pour développer une application transactionnelle par exemple. Noter qu’entre serveurs PostgreSQL, chaque version améliore les performances (notamment pour « pousser » le maximum d’informations et de critères au serveur distant). 1.2.9 SQL/MED : PERFORMANCES • Tous les FDW : vues matérialisées et indexations • postgres_fdw : fetch_size Pour améliorer les performances lors de l’utilisation de Foreign Data Wrapper, une pratique courante est de faire une vue matérialisée de l’objet distant. Les données sont récupérées en bloc et cette vue matérialisée peut être indexée. C’est une sorte de mise en cache. Évidemment cela ne convient pas à toutes les applications. La documentation de postgres_fdw3 mentionne plusieurs paramètres, et le plus intéres- sant pour des requêtes de gros volume est fetch_size : la valeur par défaut n’est que de 100, et l’augmenter permet de réduire les aller-retours à travers le réseau. 3 https://docs.postgresql.fr/current/postgres-fdw.html 21 https://dalibo.com/formations
Connexions distantes 1.2.10 SQL/MED : HÉRITAGE • Une table locale peut hériter d’une table distante et inversement • Permet le partitionnement sur plusieurs serveurs • Pour rappel, l’héritage ne permet pas de conserver : – les contraintes d’unicité et référentielles ; – les index ; – les droits. Cette fonctionnalité utilise le mécanisme d’héritage de PostgreSQL. Exemple d’une table locale qui hérite d’une table distante La table parent (ici une table distante) sera la table fgn_stock_londre et la table enfant sera la table local_stock (locale). Ainsi la lecture de la table fgn_stock_londre retournera les enregistrements de la table fgn_stock_londre et de la table local_stock. Sur l’instance distante : Créer une table stock_londre sur l’instance distante dans la base nommée « cave » et insérer des valeurs : CREATE TABLE stock_londre (c1 int); INSERT INTO stock_londre VALUES (1),(2),(4),(5); Sur l’instance locale : Créer le serveur et la correspondance des droits : CREATE EXTENSION postgres_fdw ; CREATE SERVER pgdistant FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '192.168.0.42', port '5432', dbname 'cave'); CREATE USER MAPPING FOR mon_utilisateur SERVER pgdistant OPTIONS (user 'utilisateur_distant', password 'mdp_utilisateur_distant'); Créer une table distante fgn_stock_londre correspondant à la table stock_londre de l’autre instance : CREATE FOREIGN TABLE fgn_stock_londre (c1 int) SERVER pgdistant OPTIONS (schema_name 'public' , table_name 'stock_londre'); On peut bien lire les données : 22
1. CONNEXIONS DISTANTES SELECT tableoid::regclass,* FROM fgn_stock_londre; tableoid | c1 ------------------+---- fgn_stock_londre | 1 fgn_stock_londre | 2 fgn_stock_londre | 4 fgn_stock_londre | 5 (4 lignes) Voici le plan d’exécution associé : EXPLAIN ANALYZE SELECT * FROM fgn_stock_londre; QUERY PLAN ---------------------------------------------------------------------------- Foreign Scan on fgn_stock_londre (cost=100.00..197.75 rows=2925 width=4) (actual time=0.388..0.389 rows=4 loops=1) Créer une table local_stock sur l’instance locale qui va hériter de la table mère : CREATE TABLE local_stock () INHERITS (fgn_stock_londre); On insère des valeurs dans la table local_stock : INSERT INTO local_stock VALUES (10),(15); INSERT 0 2 La table local_stock ne contient bien que 2 valeurs : SELECT * FROM local_stock ; c1 ---- 10 15 (2 lignes) En revanche, la table fgn_stock_londre ne contient plus 4 valeurs mais 6 valeurs : SELECT tableoid::regclass,* FROM fgn_stock_londre; tableoid | c1 ------------------+---- fgn_stock_londre | 1 fgn_stock_londre | 2 fgn_stock_londre | 4 fgn_stock_londre | 5 local_stock | 10 local_stock | 15 (6 lignes) Dans le plan d’exécution on remarque bien la lecture des deux tables : 23 https://dalibo.com/formations
Connexions distantes EXPLAIN ANALYZE SELECT * FROM fgn_stock_londre; QUERY PLAN ------------------------------------------------------------------------- Append (cost=100.00..233.25 rows=5475 width=4) (actual time=0.438..0.444 rows=6 loops=1) -> Foreign Scan on fgn_stock_londre (cost=100.00..197.75 rows=2925 width=4) (actual time=0.438..0.438 rows=4 loops=1) -> Seq Scan on local_stock (cost=0.00..35.50 rows=2550 width=4) (actual time=0.004..0.005 rows=2 loops=1) Planning time: 0.066 ms Execution time: 0.821 ms (5 lignes) Note : Les données de la table stock_londre sur l’instance distante n’ont pas été modi- fiées. Exemple d’une table distante qui hérite d’une table locale La table parent sera la table master_stock et la table fille (ici distante) sera la table fgn_stock_londre. Ainsi une lecture de la table master_stock retournera les valeurs de la table master_stock et de la table fgn_stock_londre, sachant qu’une lecture de la table fgn_stock_londre retourne les valeurs de la table fgn_stock_londre et local_stock. Une lecture de la table master_stock retournera les valeurs des 3 tables : master_stock, fgn_stock_londre, local_stock. Créer une table master_stock, insérer des valeurs dedans : CREATE TABLE master_stock (LIKE fgn_stock_londre); INSERT INTO master_stock VALUES (100),(200); SELECT tableoid::regclass,* FROM master_stock; tableoid | c1 --------------+----- master_stock | 100 master_stock | 200 (2 rows) Modifier la table fgn_stock_londre pour qu’elle hérite de la table master_stock : ALTER TABLE fgn_stock_londre INHERIT master_stock ; La lecture de la table master_stock nous montre bien les valeurs des 3 tables : SELECT tableoid::regclass,* FROM master_stock ; tableoid | c1 ------------------+----- master_stock | 100 24
1. CONNEXIONS DISTANTES master_stock | 200 fgn_stock_londre | 1 fgn_stock_londre | 2 fgn_stock_londre | 4 fgn_stock_londre | 5 local_stock | 10 local_stock | 15 (8 lignes) Le plan d’exécution confirme bien la lecture des 3 tables : EXPLAIN ANALYSE SELECT * FROM master_stock ; QUERY PLAN -------------------------------------------------------------------------- Append (cost=0.00..236.80 rows=5730 width=4) (actual time=0.004..0.440 rows=8 loops=1) -> Seq Scan on master_stock (cost=0.00..3.55 rows=255 width=4) (actual time=0.003..0.003 rows=2 loops=1) -> Foreign Scan on fgn_stock_londre (cost=100.00..197.75 rows=2925 width=4) (actual time=0.430..0.430 rows=4 loops=1) -> Seq Scan on local_stock (cost=0.00..35.50 rows=2550 width=4) (actual time=0.003..0.004 rows=2 loops=1) Planning time: 0.073 ms Execution time: 0.865 ms (6 lignes) Dans cet exemple, on a un héritage « imbriqué » : • la table master_stock est parent de la table distante fgn_stock_londre • la table distante fgn_stock_londre est enfant de la table master_stock et parent de la table local_stock • ma table local_stock est enfant de la table distante fgn_stock_londre master_stock ├─fgn_stock_londre => stock_londre ├─local_stock Créons un index sur master_stock et ajoutons des données dans la table master_stock : CREATE INDEX fgn_idx ON master_stock(c1); INSERT INTO master_stock (SELECT generate_series(1,10000)); Maintenant effectuons une simple requête de sélection : SELECT tableoid::regclass,* FROM master_stock WHERE c1=10; tableoid | c1 25 https://dalibo.com/formations
Connexions distantes --------------+---- master_stock | 10 local_stock | 10 (2 lignes) Étudions le plan d’exécution associé : EXPLAIN ANALYZE SELECT tableoid::regclass,* FROM master_stock WHERE c1=10; QUERY PLAN ------------------------------------------------------------------------------- Result (cost=0.29..192.44 rows=27 width=8) (actual time=0.010..0.485 rows=2 loops=1) -> Append (cost=0.29..192.44 rows=27 width=8) (actual time=0.009..0.483 rows=2 loops=1) -> Index Scan using fgn_idx on master_stock (cost=0.29..8.30 rows=1 width=8) (actual time=0.009..0.010 rows=1 loops=1) Index Cond: (c1 = 10) -> Foreign Scan on fgn_stock_londre (cost=100.00..142.26 rows=13 width=8) (actual time=0.466..0.466 rows=0 loops=1) -> Seq Scan on local_stock (cost=0.00..41.88 rows=13 width=8) (actual time=0.007..0.007 rows=1 loops=1) Filter: (c1 = 10) Rows Removed by Filter: 1 L’index ne se fait que sur master_stock. En ajoutant l’option ONLY après la clause FROM, on demande au moteur de n’afficher que la table master_stock et pas les tables filles : SELECT tableoid::regclass,* FROM ONLY master_stock WHERE c1=10; tableoid | c1 --------------+---- master_stock | 10 (1 ligne) Attention, si on supprime les données sur la table parent, la suppression se fait aussi sur les tables filles : BEGIN; DELETE FROM master_stock; -- [DELETE 10008] SELECT * FROM master_stock ; c1 ---- 26
1. CONNEXIONS DISTANTES (0 ligne) ROLLBACK; En revanche avec l’option ONLY, on ne supprime que les données de la table parent : BEGIN; DELETE FROM ONLY master_stock; -- [DELETE 10002] ROLLBACK; Enfin, si nous ajoutons une contrainte CHECK sur la table distante, l’exclusion de partition basées sur ces contraintes s’appliquent naturellement : ALTER TABLE fgn_stock_londre ADD CHECK (c1 < 100); ALTER TABLE local_stock ADD CHECK (c1 < 100); --local_stock hérite de fgn_stock_londre ! EXPLAIN (ANALYZE,verbose) SELECT tableoid::regclass,*g FROM master_stock WHERE c1=200; QUERY PLAN ------------------------------------------------------------- Result (cost=0.29..8.32 rows=2 width=8) (actual time=0.009..0.011 rows=2 loops=1) Output: (master_stock.tableoid)::regclass, master_stock.c1 -> Append (cost=0.29..8.32 rows=2 width=8) (actual time=0.008..0.009 rows=2 loops=1) -> Index Scan using fgn_idx on public.master_stock (cost=0.29..8.32 rows=2 width=8) (actual time=0.008..0.008 rows=2 loops=1) Output: master_stock.tableoid, master_stock.c1 Index Cond: (master_stock.c1 = 200) Planning time: 0.157 ms Execution time: 0.025 ms (8 rows) Attention : La contrainte CHECK sur fgn_stock_londre est locale seulement. Si cette con- trainte n’existe pas sur la table distants, le résultat de la requête pourra alors être faux ! Sur le serveur distant : INSERT INTO stock_londre VALUES (200); Sur le serveur local : SELECT tableoid::regclass,* FROM master_stock WHERE c1=200; tableoid | c1 --------------+----- 27 https://dalibo.com/formations
Connexions distantes master_stock | 200 master_stock | 200 ALTER TABLE fgn_stock_londre DROP CONSTRAINT fgn_stock_londre_c1_check; SELECT tableoid::regclass,* FROM master_stock WHERE c1=200; tableoid | c1 ------------------+----- master_stock | 200 master_stock | 200 fgn_stock_londre | 200 1.3 DBLINK • Permet le requêtage inter-bases PostgreSQL • Simple et bien documenté • En lecture seule sauf à écrire des triggers sur vue • Ne transmet pas les prédicats : tout l’objet est systématiquement récupéré • Préférer postgres_fdw Documentation officielle4 . Le module dblink de PostgreSQL a une logique différente de SQL/MED : ce dernier crée des tables virtuelles qui masquent des accès distants, alors qu’avec dblink, une requête est fournie à une fonction, qui l’exécute à distance puis renvoie le résultat. Voici un exemple d’utilisation : SELECT * FROM dblink('host=serveur port=5432 user=postgres dbname=b1', 'SELECT proname, prosrc FROM pg_proc') AS t1(proname name, prosrc text) WHERE proname LIKE 'bytea%'; L’appel à la fonction dblink() va réaliser une connexion à la base b1 et l’exécution de la requête indiquée dans le deuxième argument. Le résultat de cette requête est renvoyé comme résultat de la fonction. Noter qu’il faut nommer les champs obtenus. Généralement, on encapsule l’appel à dblink() dans une vue, ce qui donnerait par exem- ple : 4 https://docs.postgresql.fr/current/contrib-dblink-function.html 28
1. CONNEXIONS DISTANTES CREATE VIEW pgproc_b1 AS SELECT * FROM dblink('host=serveur port=5432 user=postgres dbname=b1', 'SELECT proname, prosrc FROM pg_proc') AS t1(proname name, prosrc text); SELECT * FROM pgprocb1 WHERE proname LIKE 'bytea%'; Un problème est que, rapidement, on ne se rappelle plus que c’est une table externe et que, même si le résultat contient peu de lignes, tout le contenu de la table distante est récupérés avant que le filtre ne soit exécuté. Donc même s’il y a un index qui aurait pu être utilisé pour ce prédicat, il ne pourra pas être utilisé. Il est rapidement difficile d’obtenir de bonnes performances avec cette extension. Noter que dblink n’est pas aussi riche que son homonyme dans d’autres SGBD concur- rents. De plus, cette extension est un peu ancienne et ne bénéficie pas de nouvelles fonc- tionnalités sur les dernières versions de PostgreSQL. On préférera utiliser à la place l’implémentation de SQL/MED de PostgreSQL et le Foreign Data Wrapper postgres_fdw qui évoluent de concert à chaque version majeure et deviennent de plus en plus puis- sants au fil des versions. Cependant, dblink a encore l’intérêt d’émuler des transactions autonomes ou d’appeler des fonctions sur le serveur distant, ce qui est impossible directement avec postgres_fdw. dblink fournit quelques fonctions plus évoluées que l’exemple ci-dessus, décrites dans la documentation5 . 1.4 PL/PROXY • Langage de procédures – développée à la base par Skype • Fonctionnalités – connexion à un serveur ou à un ensemble de serveurs – exécution de fonctions, pas de requêtes • Possibilité de distribuer les requêtes • Utile pour le « partionnement horizontal » 5 https://docs.postgresql.fr/current/dblink.html 29 https://dalibo.com/formations
Connexions distantes • Uniquement si votre application n’utilise que des appels de fonction – dans le cas contraire, il faut revoir l’application PL/Proxy propose d’exécuter une fonction suivant un mode parmi trois : • ANY : la fonction est exécutée sur un seul nœud au hasard • ALL : la fonction est exécutée sur tous les nœuds • EXACT : la fonction est exécutée sur un nœud précis, défini dans le corps de la fonction On peut mettre en place un ensemble de fonctions PL/Proxy pour « découper » une table volumineuse et la répartir sur plusieurs instances PostgreSQL. Le langage PL/Proxy offre alors la possibilité de développer une couche d’abstraction transparente pour l’utilisateur final qui peut alors consulter et manipuler les données comme si elles se trouvaient dans une seule table sur une seule instance PostgreSQL. On peut néanmoins se demander l’avenir de ce projet. La dernière version date de septem- bre 2020, et il n’y a eu aucune modification des sources depuis cette version. La société qui a développé ce langage au départ a été rachetée par Microsoft. Le développement du langage dépend donc d’un très petit nombre de contributeurs. 1.5 CONCLUSION • Privilégier SQL/MED • dblink et PL/Proxy en perte de vitesse – à n’utiliser que s’ils résolvent un problème non gérable avec SQL/MED 30
1. CONNEXIONS DISTANTES 1.6 TRAVAUX PRATIQUES 1.6.1 FOREIGN DATA WRAPPER SUR UN FICHIER Avec le foreign data wrapper file_fdw, créez une table distante qui présente les champs du fichier /etc/passwd sous forme de table. Vérifiez son bon fonctionnement avec un SELECT. 1.6.2 FOREIGN DATA WRAPPER SUR UNE AUTRE BASE Accédez à la table stock de votre voisin à travers une table dis- tante (via postgres_fdw) : configuration du pg_hba.conf, instal- lation de l’extension, création du serveur, de la table, du map- ping pour les droits. Visualisez l’accès par un EXPLAIN ANALYZE VERBOSE SELECT .... 31 https://dalibo.com/formations
Connexions distantes 1.7 TRAVAUX PRATIQUES (SOLUTIONS) 1.7.1 FOREIGN DATA WRAPPER SUR UN FICHIER Avec le foreign data wrapper file_fdw, créez une table distante qui présente les champs du fichier /etc/passwd sous forme de table. Vérifiez son bon fonctionnement avec un SELECT. CREATE EXTENSION file_fdw; CREATE SERVER files FOREIGN DATA WRAPPER file_fdw; CREATE FOREIGN TABLE passwd ( login text, passwd text, uid int, gid int, username text, homedir text, shell text) SERVER files OPTIONS (filename '/etc/passwd', format 'csv', delimiter ':'); 1.7.2 FOREIGN DATA WRAPPER SUR UNE AUTRE BASE Accédez à la table stock de votre voisin à travers une table dis- tante (via postgres_fdw) : configuration du pg_hba.conf, instal- lation de l’extension, création du serveur, de la table, du map- ping pour les droits. Visualisez l’accès par un EXPLAIN ANALYZE VERBOSE SELECT .... Tout d’abord, vérifiez qu’avec psql vous arrivez à vous connecter chez lui. Sinon, vérifiez son listen_addresses, son fichier pg_hba.conf, son firewall. Une fois que la connexion avec psql fonctionne, vous pouvez entamer la création de la table distante stock_remote chez votre voisin. Attention, si vous avez fait le TP partition- nement précédemment, accédez plutôt à stock_old. Installez d’abord le foreign data wrapper : CREATE EXTENSION postgres_fdw ; Créez le foreign server (déclaration du serveur de votre voisin). Ajustez les options pour correspondre à votre environnement : 32
1. CONNEXIONS DISTANTES CREATE SERVER serveur_voisin FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '192.168.0.18', port '5432', dbname 'cave'); Créez un user mapping, c’est-à-dire une correspondance entre votre utilisateur local et l’utilisateur distant : CREATE USER MAPPING FOR mon_utilisateur SERVER serveur_voisin OPTIONS (user 'utilisateur_distant', password 'mdp_utilisateur_distant'); Puis créez votre foreign table : CREATE FOREIGN TABLE stock_voisin ( vin_id integer, contenant_id integer, annee integer, nombre integer) SERVER serveur_voisin OPTIONS (schema_name 'public', table_name 'stock_old'); Vérifiez le bon fonctionnement : SELECT * FROM stock_voisin WHERE vin_id=12; Vérifiez le plan : EXPLAIN ANALYZE VERBOSE SELECT * FROM stock_voisin WHERE vin_id=12; Il faut l’option VERBOSE pour voir la requête envoyée au serveur distant. Vous constatez que le prédicat sur vin_id a été transmis, ce qui est le principal avantage de cette implé- mentation sur les DBLinks. 33 https://dalibo.com/formations
NOTES
NOTES
NOTES
NOTES
NOS AUTRES PUBLICATIONS FORMATIONS • DBA1 : Administra on PostgreSQL https://dali.bo/dba1 • DBA2 : Administra on PostgreSQL avancé https://dali.bo/dba2 • DBA3 : Sauvegardes et réplica on avec PostgreSQL https://dali.bo/dba3 • DEVPG : Développer avec PostgreSQL https://dali.bo/devpg • DEVSQLPG : SQL pour PostgreSQL https://dali.bo/devsqlpg • PERF1 : PostgreSQL Performances https://dali.bo/perf1 • PERF2 : Indexa on et SQL avancé https://dali.bo/perf2 • MIGORPG : Migrer d’Oracle vers PostgreSQL https://dali.bo/migorpg LIVRES BLANCS • Migrer d’Oracle à PostgreSQL • Industrialiser PostgreSQL • Bonnes pra ques de modélisa on avec PostgreSQL • Bonnes pra ques de développement avec PostgreSQL TÉLÉCHARGEMENT GRATUIT Les versions électroniques de nos publica ons sont disponibles gratuitement sous licence open-source ou sous licence Crea ve Commons. Contactez-nous à l’adresse contact@ dalibo.com pour plus d’informa on.
DALIBO, L’EXPERTISE POSTGRESQL Depuis 2005, DALIBO met à la disposi on de ses clients son savoir-faire dans le domaine des bases de données et propose des services de conseil, de forma on et de support aux entreprises et aux ins tu onnels. En parallèle de son ac vité commerciale, DALIBO contribue aux développements de la communauté PostgreSQL et par cipe ac vement à l’anima on de la communauté fran- cophone de PostgreSQL. La société est également à l’origine de nombreux ou ls libres de supervision, de migra on, de sauvegarde et d’op misa on. Le succès de PostgreSQL démontre que la transparence, l’ouverture et l’auto-ges on sont à la fois une source d’innova on et un gage de pérennité. DALIBO a intégré ces principes dans son ADN en optant pour le statut de SCOP : la société est contrôlée à 100 % par ses salariés, les décisions sont prises collec vement et les bénéfices sont partagés à parts égales.
Vous pouvez aussi lire