Резюме / TL;DR
В 3 стъпки ще можете да изпълните много лесно:
INSERT INTO production_db.table_name
SELECT * FROM backup_db.table_name -- backup_db being remote
Първо инсталирайте резервното копие локално, второ вземете SQL скрипт, трето отворете локалния си хост към външния свят с ngrok .
Да тръгваме?
1. Изтеглете своя дъмп файл на Heroku и го изхвърлете някъде:
- Можете да направите това в отдалечена база данни, ако имате налични сървъри. Но ако като мен не искате да предоставите друга производствена база данни на Heroku или някъде другаде, локално ще е напълно достатъчно.
- Обичам да използвам PGAdmin
(налично за Linux, Mac и Windows), но с помощта на команден ред и
psql
също ще свърши работа (като прочетете това публикация чрез пример) - В PGAdmin бихте направили
Create a database
. След това щракнете с десния бутон върху него и използвайтеrestore
функция. Изберете вашия дъмп файл, щракнете върхуRestore
и всичко е готово:вашите резервни данни са налични локално! Добра работа!
2. Достъп до него от вашата отдалечена база данни
Исках да направя следното:
SELECT * FROM backup_db.table_name
-- So I could then do
INSERT INTO production_db.table_name
SELECT * FROM backup_db.table_name
И щях да съм готов. Супер лесно, нали? Доста очевидно? Това трябва да е правено вече стотици пъти. Ами не!
Има помощна програма, наречена db_link
в Postgres 9.1+, но е доста ограничаващо, тъй като се прилага следният синтаксис:
SELECT fname, lname FROM db_link('host=localhost dbname=backup-28-08', 'SELECT fname, lname FROM users') AS remote (varchar255 fname varchar255 lname)
Всяко име на колона трябва да се повтори два пъти, включително нейния тип. Доста тежко, далеч сме от простия SELECT * FROM backup_db.table_name
Така че идеята тук е да се използва information_schema
съдържание на таблица, което описва всяка таблица с нейните имена на колони, нейните типове и т.н. Намерих този въпрос на SO:Посочете списък с дефиниции на колони dblink от локален съществуващ тип
което ми помогна много (Благодаря bentrm
).
Но решението му беше процес от две стъпки, първо генериране на функция, след което запитване към нея:
SELECT dblink_star_func('dbname=ben', 'public', 'test');
SELECT * FROM star_test() WHERE data = 'success';
И пак се бях насочил към 1 лайнер. След малко болка (не съм SQL гуру), ето същността:https://gist.github. com/augnustin/d30973ea8b5bf0067841
Сега мога да направя:
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)
Страхотно, нали?
3. Отдалечен достъп до localhost
Ако вашата отдалечена база данни вече е достъпна от интернет (=има IP адрес, име на домейн, напр. за Heroku, тя ще изглежда така:ec2-54-217-229-169.eu-west-1.compute.amazonaws.com:5672/df68cfpbufjd9p
) можете да пропуснете тази стъпка . Но ако използвате вашата локална база данни, трябва да я направите достъпна от външния свят (така че базата данни на Heroku да има достъп до нея).
За целта използвам прекрасния ngrok .
Веднъж инсталиран, трябва само да въведа следната команда:
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
И ще трябва само да включите db_link
(в същността) към host=ngrock.com port=51727
и сте готови за работа !
4. Продължаваме по-нататък
Има много възможни подобрения за това. Ето някои, които вече виждам:
- Разглеждане на скрипта като функция по подразбиране за
db_link
функция - Бъдете по-устойчиви на грешки, ако структурите на базата данни са различни при архивиране и производство
- Създаване на инструмент за сравнение между резултатите от базата данни и резултатите от архивиране (за връщане само на различни редове)
- Работа с прости съединения
- И още повече би било да има адаптер на ниво приложение (напр. ActiveRecord в Rails), който може да позволи манипулиране на бекенд обекти вместо необработен SQL, както сега
Дано бях ясен! Моля, попитайте за повече подробности в противен случай