web-dev-qa-db-fra.com

Comment travailler avec plusieurs bases de données Postgres dans psycopg2

J'ai deux bases de données Postgres différentes sur deux serveurs différents (l'un est en fait local). Similaire à cette question , je voudrais travailler avec les deux bases de données en même temps. Cependant, je ne peux pas trouver un moyen de le faire en utilisant psycopg2.

Je pensais donc que j'avais probablement besoin de deux curseurs différents:

conn_local = psycopg2.connect(dbname='local_db', Host='localhost')
conn_remote = psycopg2.connect(dbname='remote_db', Host='some.other.server')

curs_local = conn_local.cursor()
curs_remote = conn_remote.cursor()

Mais comment puis-je adresser ces bases de données? Par exemple, lorsque j'essaye de joindre des données des deux tables:

curs_local.execute("""
    CREATE TABLE local_db.public.newtable AS
    SELECT remote_db.public.remotetable.rcolumn AS col_from_remote, 
    local_db.public.localtable.lcolumn AS col_from_local
    FROM remote_db.public.remotetable, local_db.public.localtable""")

Il y aura une erreur dans le style de psycopg2.NotSupportedError: cross-database references are not implemented: "local_db.public.new_table". Le ATTACH TABLE (comme décrit dans la solution ici ) n'existe apparemment pas dans Postgres/psycopg2.

Est-il possible de travailler avec plusieurs bases de données à la fois? Comment? Ou vais-je devoir copier (exporter/importer) les données de remote_db à local_db première?

7
n1000

Oui, il est possible de travailler avec plusieurs bases de données en même temps mais vous cherchez au mauvais endroit. psycopg2 n'est qu'une bibliothèque qui simplifie l'accès et la manipulation des données provenant de PostgreSQL, mais elle ne va pas bien au-delà de ce que vous pouvez faire avec psql. Ce que vous cherchez à faire, vous pouvez le résoudre au niveau de la base de données en utilisant Foreign Data Wrappers .

Cela devient plus compliqué dans votre définition de schéma mais apporte des tables distantes de l'hôte some.other.server base de données remote_db pour apparaître comme s'ils vivaient sur localhost dans la base de données local_db. Un exemple simple sur la façon de connecter les wrappers:

CREATE EXTENSION postgres_fdw;
CREATE SERVER some_remote_server 
  FOREIGN DATA WRAPPER postgres_fdw 
  OPTIONS (Host 'some.remote.server', port '5432', dbname 'remote_db');
CREATE USER MAPPING FOR local_user 
  SERVER some_remote_server 
  OPTIONS (user 'remote_user', password 'remote_user_password');
CREATE FOREIGN TABLE local_table_name (id int, value int) 
  SERVER some_remote_server 
  OPTIONS ( schema_name 'remote_schema_name', table_name 'remote_table_name');

Maintenant, localement, vous pouvez simplement exécuter

SELECT * from local_table_name

et la requête sera exécutée sur l'hôte distant. Il va sans dire que cela nécessite une connectivité entre les deux serveurs.

De même, si vous le devez vraiment, vous pouvez créer un serveur "distant" par rapport à l'hôte local et pointer vers une autre base de données locale pour les requêtes entre bases de données. Se sent sale mais c'est possible.

Comme l'a mentionné @a_horse_with_no_name, ce n'est pas très efficace. Si vous faites cela trop fréquemment, vous n'obtenez pas les performances les plus optimales et vous feriez mieux d'avoir de très bonnes raisons de garder vos bases de données séparées à ce stade.

7
ats

PostgreSQL appelle des "schémas" ce que MySQL appelle des bases de données. Ne créez pas plusieurs bases de données avec l'intention de travailler ensemble. Cela dit, si vous avez besoin d'accéder à une base de données externe, le FDW PostgreSQL vous aidera

3
Evan Carroll

Comme je viens de l'apprendre de cette réponse , une approche alternative serait dblink . Par exemple.:

SELECT *
FROM dblink('dbname=mydb', 'select rcol1, rcol2 from remote_db')
  AS t1(rcol1 name, rcol2 text)
1
n1000