Oversigt / TL;DR
I 3 trin vil du være i stand til at udføre meget enkelt:
INSERT INTO production_db.table_name
SELECT * FROM backup_db.table_name -- backup_db being remote
Først skal du installere sikkerhedskopien lokalt, for det andet få et SQL-script, for det tredje åbne din lokale vært til omverdenen med ngrok .
Lad os gå?
1. Download din dump-fil på Heroku og dump det et sted:
- Du kan gøre det på en ekstern database, hvis du har nogle servere til rådighed. Men hvis du ligesom mig ikke ønsker at klargøre en anden produktionsdatabase på Heroku eller et andet sted, vil lokalt helt gøre det.
- Jeg kan godt lide at bruge PGAdmin
(tilgængelig på Linux, Mac og Windows), men ved hjælp af kommandolinje og
psql
vil også gøre det (ved at læse denne indlæg ved eksempel) - I PGAdmin skal du
Create a database
. Højreklik derefter på den og brugrestore
fungere. Vælg din dumpfil, klik påRestore
og du er klar:dine backupdata er tilgængelige lokalt! Godt arbejde!
2. Få adgang til den fra din fjerndatabase
Jeg ønskede at gøre følgende:
SELECT * FROM backup_db.table_name
-- So I could then do
INSERT INTO production_db.table_name
SELECT * FROM backup_db.table_name
Og jeg ville være klar. Super nemt, ikke? Ret indlysende? Dette må allerede være blevet gjort hundredvis af gange. Nå, nej!
Der er et hjælpeprogram kaldet db_link
i Postgres 9.1+, men det er ret begrænsende, da følgende syntaks gælder:
SELECT fname, lname FROM db_link('host=localhost dbname=backup-28-08', 'SELECT fname, lname FROM users') AS remote (varchar255 fname varchar255 lname)
Hvert kolonnenavn skal gentages to gange inklusive dens type. Temmelig tungt, vi er langt fra den simple SELECT * FROM backup_db.table_name
Så ideen her er at bruge information_schema
tabelindhold, som beskriver hver tabel med dens kolonnenavne, dens typer osv. Jeg fandt dette spørgsmål på SO:Angiv dblink-kolonnedefinitionsliste fra en lokal eksisterende type
hvilket hjalp mig meget (Tak bentrm
).
Men dens løsning var en proces i to trin, først generering af en funktion og derefter forespørgsel på den:
SELECT dblink_star_func('dbname=ben', 'public', 'test');
SELECT * FROM star_test() WHERE data = 'success';
Og jeg sigtede stadig efter en 1 liner. Efter lidt smerte (ikke at være en SQL-guru), her er hovedindholdet:https://gist.github. com/augnustin/d30973ea8b5bf0067841
Jeg kan nu:
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)
Fantastisk, ikke?
3. Få fjernadgang til localhost
Hvis din fjerndatabase allerede er tilgængelig fra internettet (=har en IP-adresse, et domænenavn F.eks. for Heroku vil det se ud som:ec2-54-217-229-169.eu-west-1.compute.amazonaws.com:5672/df68cfpbufjd9p
) du kan springe dette trin over . Men hvis du bruger din lokale database, skal du gøre den tilgængelig fra omverdenen (så Heroku-databasen kan få adgang til den).
Til dette bruger jeg den vidunderlige ngrok .
Når den er installeret, behøver jeg kun at indtaste følgende kommando:
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
Og du behøver kun at tilslutte db_link
(i det væsentlige) til host=ngrock.com port=51727
og du er god til at gå !
4. Gå videre
Der er mange mulige forbedringer til dette. Her er nogle, jeg allerede ser:
- Betragtning af scriptet som en standardfunktion til
db_link
funktion - Vær mere fejlsikker, hvis databasestrukturer er forskellige i backup og produktion
- Sådan laves sammenligningsværktøj mellem databaseresultater og backupresultater (for kun at returnere forskellige linjer)
- Håndter simple joins
- Og endnu mere ville være at have en applikationsniveauadapter (f.eks. ActiveRecord in Rails), der kunne tillade manipulation af backend-objekter i stedet for rå SQL som nu
Håber jeg var klar! Spørg venligst om flere detaljer ellers