情况:
我有一个PostgreSQL数据库,它从现场部署的单元中的传感器记录数据(让我们称之为 源数据库 )。该单元具有非常有限的硬盘空间,这意味着如果保持不变,数据记录将导致数据库所在的磁盘在一周内填满。我有一个(非常有限的)数据库的网络链接(所以我想压缩转储文件),在所述链接的另一边我有另一个PostgreSQL数据库(让我们称之为 < em>目标数据库 ),它有很多可用空间(为了论证,请说源的空间非常有限,而且目的地在空间方面是无限的。)
我需要对源数据库进行增量备份,将自上次备份以来添加的行追加到目标数据库,然后从源数据库中清除添加的行。
现在,自上次备份以来,源数据库可能已清除,也可能未清除,因此目标数据库只能在自动(脚本)进程中导入新行,但pg_restore
失败尝试从与目标数据库具有相同主键号的转储进行还原时,可悲。
所以问题是:
仅从源中还原目标数据库中的行的最佳方法是什么?
到目前为止,我提出的唯一解决方案是pg_dump
数据库并使用pg_restore
将转储恢复到目标端的新辅助数据库,然后使用简单sql
来整理主目标数据库中已存在的行。但似乎应该有更好的方式......
(额外问题:在这样的应用程序中使用PostgreSQL我完全错了吗?我可以接受其他数据收集替代方案的建议......)
答案 0 :(得分:1)
一种好的开始方式可能是使用--inserts
选项pg_dump
。从文档(强调我的):
将数据转储为INSERT命令(而不是COPY)。这将使 恢复很慢;它主要用于制作可以转储的转储 被加载到非PostgreSQL数据库中。 但是,因为这个选项 为每一行生成一个单独的命令,重新加载一行时出错 导致只丢失该行而不是整个表格内容。 请注意,如果重新排列,恢复可能会完全失败 列顺序。 --column-inserts选项对列顺序是安全的 变化,但更慢。
我目前无法使用pg_restore
对其进行测试,但这可能适合您的情况。
您还可以使用从版本9.5开始,PostgreSQL为INSERT提供ON CONFLICT DO ...的事实。使用简单的脚本语言将这些添加到转储中,你应该没问题。遗憾的是,我没有找到pg_dump
自动添加这些选项的选项。
答案 1 :(得分:1)
您可能会谷歌“偶尔连接数据库同步”以查看相关解决方案。
据我所知,这不是一个整齐解决的问题 - 有一些常见的解决方法,但我不知道以数据库为中心的开箱即用解决方案。
最常见的处理方法是使用消息总线在您的计算机之间移动事件。例如,如果您的“源数据库”只是一个数据存储,没有其他逻辑,您可以摆脱它,并使用消息总线说“事件x已发生”,并指向该消息总线的端点您的“目标计算机”,然后将其写入您的数据库。
您可以考虑Apache ActiveMQ或阅读“Patterns of enterprise integration”。
答案 2 :(得分:0)
#!/bin/sh
PSQL=/opt/postgres-9.5/bin/psql
TARGET_HOST=localhost
TARGET_DB=mystuff
TARGET_SCHEMA_IMPORT=copied
TARGET_SCHEMA_FINAL=final
SOURCE_HOST=192.168.0.101
SOURCE_DB=slurpert
SOURCE_SCHEMA=public
########
create_local_stuff()
{
${PSQL} -h ${TARGET_HOST} -U postgres ${TARGET_DB} <<OMG0
CREATE SCHEMA IF NOT EXISTS ${TARGET_SCHEMA_IMPORT};
CREATE SCHEMA IF NOT EXISTS ${TARGET_SCHEMA_FINAL};
CREATE TABLE IF NOT EXISTS ${TARGET_SCHEMA_FINAL}.topic
( topic_id INTEGER NOT NULL PRIMARY KEY
, topic_date TIMESTAMP WITH TIME ZONE
, topic_body text
);
CREATE TABLE IF NOT EXISTS ${TARGET_SCHEMA_IMPORT}.tmp_topic
( topic_id INTEGER NOT NULL PRIMARY KEY
, topic_date TIMESTAMP WITH TIME ZONE
, topic_body text
);
OMG0
}
########
find_highest()
{
${PSQL} -q -t -h ${TARGET_HOST} -U postgres ${TARGET_DB} <<OMG1
SELECT MAX(topic_id) FROM ${TARGET_SCHEMA_IMPORT}.tmp_topic;
OMG1
}
########
fetch_new_data()
{
watermark=${1-0}
echo ${watermark}
${PSQL} -h ${SOURCE_HOST} -U postgres ${SOURCE_DB} <<OMG2
\COPY (SELECT topic_id, topic_date, topic_body FROM ${SOURCE_SCHEMA}.topic WHERE topic_id >${watermark}) TO '/tmp/topic.dat';
OMG2
}
########
insert_new_data()
{
${PSQL} -h ${TARGET_HOST} -U postgres ${TARGET_DB} <<OMG3
DELETE FROM ${TARGET_SCHEMA_IMPORT}.tmp_topic WHERE 1=1;
COPY ${TARGET_SCHEMA_IMPORT}.tmp_topic(topic_id, topic_date, topic_body) FROM '/tmp/topic.dat';
INSERT INTO ${TARGET_SCHEMA_FINAL}.topic(topic_id, topic_date, topic_body)
SELECT topic_id, topic_date, topic_body
FROM ${TARGET_SCHEMA_IMPORT}.tmp_topic src
WHERE NOT EXISTS (
SELECT *
FROM ${TARGET_SCHEMA_FINAL}.topic nx
WHERE nx.topic_id = src.topic_id
);
OMG3
}
########
delete_below_watermark()
{
watermark=${1-0}
echo ${watermark}
${PSQL} -h ${SOURCE_HOST} -U postgres ${SOURCE_DB} <<OMG4
-- delete not yet activated; COUNT(*) instead
-- DELETE
SELECT COUNT(*)
FROM ${SOURCE_SCHEMA}.topic WHERE topic_id <= ${watermark}
;
OMG4
}
######## Main
#create_local_stuff
watermark="`find_highest`"
echo 'Highest:' ${watermark}
fetch_new_data ${watermark}
insert_new_data
echo 'Delete below:' ${watermark}
delete_below_watermark ${watermark}
# Eof
这只是一个例子。一些说明:
postgres
运行,您可能需要更改此count(*)