Résumé / TL;DR
En 3 étapes vous pourrez exécuter très simplement :
INSERT INTO production_db.table_name
SELECT * FROM backup_db.table_name -- backup_db being remote
Installez d'abord la sauvegarde localement, deuxièmement obtenez un script SQL, troisièmement ouvrez votre hôte local au monde extérieur avec ngrok .
Allons-y ?
1. Téléchargez votre fichier de vidage sur Heroku et déposez-le quelque part :
- Vous pouvez le faire sur une base de données distante si vous avez des serveurs disponibles. Mais si, comme moi, vous ne souhaitez pas provisionner une autre base de données de production sur Heroku ou ailleurs, cela suffira en local.
- J'aime utiliser PGAdmin
(disponible sur Linux, Mac et Windows), mais en utilisant la ligne de commande et
psql
fera également (en lisant ceci poster par exemple) - Dans PGAdmin, vous feriez
Create a database
. Ensuite, faites un clic droit dessus et utilisez lerestore
fonction. Sélectionnez votre fichier de vidage, cliquez surRestore
et le tour est joué :vos données de sauvegarde sont disponibles localement ! Bon travail !
2. Accédez-y depuis votre base de données distante
Je voulais faire ce qui suit :
SELECT * FROM backup_db.table_name
-- So I could then do
INSERT INTO production_db.table_name
SELECT * FROM backup_db.table_name
Et je serais prêt. Super facile, non ? Assez évident? Cela a dû déjà être fait des centaines de fois. Et bien non !
Il existe un utilitaire appelé db_link
dans Postgres 9.1+, mais c'est assez contraignant car la syntaxe suivante s'applique :
SELECT fname, lname FROM db_link('host=localhost dbname=backup-28-08', 'SELECT fname, lname FROM users') AS remote (varchar255 fname varchar255 lname)
Chaque nom de colonne doit être répété deux fois, y compris son type. Assez lourd, on est loin du simple SELECT * FROM backup_db.table_name
Donc l'idée ici est d'utiliser le information_schema
contenu de la table, qui décrit chaque table avec ses noms de colonnes, ses types, etc. J'ai trouvé cette question sur SO :Spécifier la liste de définition de colonne dblink à partir d'un type existant local
qui m'a beaucoup aidé (Merci bentrm
).
Mais sa solution était un processus en deux étapes, générant d'abord une fonction, puis l'interrogeant :
SELECT dblink_star_func('dbname=ben', 'public', 'test');
SELECT * FROM star_test() WHERE data = 'success';
Et je visais toujours un 1 ligne. Après un peu de peine (n'étant pas un gourou du SQL), voici le Gist :https://gist.github. com/augnustin/d30973ea8b5bf0067841
Je peux maintenant faire :
SELECT * FROM remote_db(NULL::users) -- (Still not 100% about why I need the NULL::)
-- And also
INSERT INTO users
SELECT * FROM remote_db(NULL::users)
Génial, non ?
3. Accéder à distance à localhost
Si votre base de données distante est déjà disponible sur Internet (=a une adresse IP, un nom de domaine Par exemple, pour Heroku, cela ressemblera à :ec2-54-217-229-169.eu-west-1.compute.amazonaws.com:5672/df68cfpbufjd9p
) vous pouvez ignorer cette étape . Mais si vous utilisez votre base de données locale, vous devez la rendre disponible depuis le monde extérieur (afin que la base de données Heroku puisse y accéder).
Pour cela, j'utilise le merveilleux ngrok .
Une fois installé, il me suffit d'entrer la commande suivante :
ngrok -proto=tcp 5432 #5432 being the default port for Postgresql. (Adapt if necessary)
Tunnel Status online
Version 1.7/1.6
Forwarding tcp://ngrok.com:51727 -> 127.0.0.1:5432
Web Interface 127.0.0.1:4040
# Conn 0
Avg Conn Time 0.00ms
Et vous n'auriez qu'à brancher db_link
(dans l'essentiel) à host=ngrock.com port=51727
et vous êtes prêt à partir !
4. Aller plus loin
Il y a beaucoup d'améliorations possibles à cela. En voici quelques-unes que je vois déjà :
- Considérer le script comme une fonctionnalité par défaut de
db_link
fonction - Être plus à l'épreuve des erreurs si les structures de base de données sont différentes en sauvegarde et en production
- Création d'un outil de comparaison entre les résultats de la base de données et les résultats de la sauvegarde (pour ne renvoyer que des lignes différentes)
- Gérer les jointures simples
- Et encore plus serait d'avoir un adaptateur au niveau de l'application (par exemple, ActiveRecord dans Rails) qui pourrait permettre la manipulation d'objets backend au lieu de SQL brut comme maintenant
J'espère avoir été clair ! Veuillez demander plus de détails sinon