LINUX.ORG.RU
решено ФорумAdmin

Развернуть дамп с обновлением существующих записей

 


1

2

Имеется такая задача:

Дано: два сервера на каждом PostgreSQL: один рабочий, на нём PostgreSQL 8.4.9, второй планируется для формирования отчётов и т.п. дел, допускающих некоторую задержку с обновлением данных, сейчас версия PostgreSQL 9.1.11.

Требуется: раз в день их синхронизировать - забирать с рабочего дампы необходимых таблиц и разворачивать их на втором сервере с добавлением новых записей и обновлением существующих, всё это скриптами по крону.

Сейчас это сделано скриптами, отчасти костыльно. Можно-ли как-то развернуть дамп отдельной таблицы с обновлением уже имеющегося? На stackoverflow попался вариант с truncate:

pg_dump -t table1 production_database >/tmp/old_production_database_table1.sql
pg_dump -t table1 devel_database >/tmp/devel_database_table1.sql
psql production_database
truncate table1
\i /tmp/devel_database_table1.sql
\i /tmp/old_production_database_table1.sql
Интересует, какие еще есть варианты? Может быть более подходящие для данного случая?


Не проще ли настроить репликацию между постгресами одной версии?

anonymous
()
Ответ на: комментарий от anonymous

Такой вариант в будущем возможен, но не сейчас.

На данный момент ситуация такая: серваки друг друга напрямую вообще не видят; подготовка бекапов вообще на третьем происходит, откуда они забираются scp.

Про извращения всё понятно, но приходится работать с тем, что есть.

igor87
() автор топика

Вопрос, в общем, можно-ли как-то развернуть дамп с обновлением имеющихся записей. Иные варианты, в том числе репликация, были отвергнуты в силу разных причин. В частности репликация из-за того, что 1) серваки друг друга не видят; 2) в рабочей базе часть данных будет периодически удаляться, но во второй они должны остаться.

igor87
() автор топика
Ответ на: комментарий от igor87

В таких случаях я горожу скрипт или приложение на коленке, которое дампает из одной базы в csv, а потом инсертит из csv во вторую.

anonymous
()
Ответ на: комментарий от igor87

2) в рабочей базе часть данных будет периодически удаляться, но во второй они должны остаться.

В таком случае без самописного костыля не обойтись, имхо.

technoid
()
Ответ на: комментарий от technoid

Самописный костыль имеется. Думал, что может есть что-то более «правильное» и «родное» для postgres на такой случай.

igor87
() автор топика

В общем, решил остановиться на варианте c csv-файлами и временными таблицами:

На втором сервере, на котором находится дополнительная база, назовем его A, запускается sh-скрипт который:

1) копирует на третий(промежуточный) сервер, который виден обоим серверам, пусть будет C, скрипт с помощью scp;

2) на сервере C запускает скрипт из (1), который готовит csv-файлы с бекапами таблиц и один json-файл с содержанием: какая таблица в каком файле, primary key таблицы и, главное, таблицы отсортированы в нужном порядке, чтобы при развертывании не возникло проблем с foreign key. CSV-файлы генерируются psql-ом с параметром HEADER. Данные забираются с сервера B, где расположена рабочая база;

3) забирает сгенерированные в (2) данные с помощью scp на сервер A;

4) запускается еще один скрипт, уже на сервере A, который генерирует SQL-транзакции и потом скармливает их поочередно psql'у:

CREATE TABLE <название временной таблицы> AS SELECT * FROM <название таблицы>;
\copy <название временной таблицы>(<поля таблицы, составляются из заголовка csv-файла>) FROM '<имя csv-файла>' WITH DELIMITER ';' CSV HEADER;
CREATE FUNCTION fill_<название временной таблицы>() RETURNS VOID AS
$$
DECLARE
    data record;
BEGIN
    FOR data IN SELECT * FROM <название временной таблицы>
    LOOP
        IF EXISTS (SELECT * FROM <название таблицы> WHERE {condition}) THEN
            UPDATE <название таблицы> SET
{fields_values}
            WHERE <сравнение по primary key>;
        ELSE
            INSERT INTO <название таблицы>(<поля таблицы>)
            VALUES (<поля переменной data, совпадает с полями таблицы, но начинается с "data.">);
        END IF;
    END LOOP;
END;
$$ language plpgsql;
SELECT fill_<название временной таблицы>();
DROP FUNCTION fill_<название временной таблицы>();
DROP TABLE <название временной таблицы>;

На дополнительной базе все триггеры у синхронизируемых таблиц отключены. С учетом, что эта база используется мало, в отличие от рабочей, транзакции отрабатывают довольно-таки шустро.

igor87
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.