将表从数据库移动到另一个 - 仅插入缺少的行

时间:2017-09-12 13:02:05

标签: postgresql

我有两个相似的数据库,一个名为datastore,另一个名为datarestore

datarestoredatastore的副本,是从备用图片创建的。问题是我不小心从datastore删除了太多数据。

两个数据库都位于不同的AWS实例上,我通常使用pgAdmin III或Python连接它们来创建处理数据的脚本。

我想将datastoredatarestore意外删除的行datastore转换为pgAdmin III。有没有人知道如何实现这一目标。两个数据库都包含接近1.000.000.000行,并且版本为9.6。

我在----------------------------------------------------- | id (serial - auto incrementing int) | - primary key | did (varchar) | | sensorid (int) | | timestamp (bigint) | | data (json) | | db_timestamp (bigint) | ----------------------------------------------------- 内看到了一些备份/导入/恢复选项,我只是不知道它们是如何工作的,以及它们是否支持我的需求?我还考虑过创建一个python脚本,但查询我的数据库变得非常慢,所以这似乎也不是一个选项。

NotificationCenter.default.addObserver(
        self,
        selector: #selector(self.addressBookDidChange),
        name: NSNotification.Name.CNContactStoreDidChange,
        object: nil)

1 个答案:

答案 0 :(得分:2)

如果您在这些数据库之间保留了主键,那么您可以create foreign tablesdatarestore指向datastore并检查缺少哪些键(例如使用select pk from old_table except select pk from new_table)并获取使用您创建的相同外表的那些缺少的行。这应该限制您首次检查丢失的PK只是仅索引扫描(+网络传输),然后它将是索引扫描以获取丢失的数据。如果你只缺少它的一小部分,那么它不应该花很长时间。

如果您需要更详细的示例,我会更新我的答案。

编辑:

外部表/服务器使用示例

这些命令需要在datarestore(或datastore上展开,如果您选择推送数据而不是拉动数据。)

如果您还没有安装外部数据包装器:

CREATE EXTENSION postgres_fdw;

这将在datarestore主机上创建虚拟服务器。它只是指向外部服务器的一些元数据:

CREATE SERVER foreign_datastore FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'foreign_hostname', dbname 'foreign_database_name',
         port '5432_or_whatever_you_have_on_datastore_host');

这将告诉您的datarestore主机在服务器foreign_datastore上使用fdw时应该连接哪个用户。它仅用于your_local_role_name登录的datarestore

CREATE USER MAPPING FOR your_local_role_name SERVER foreign_datastore 
OPTIONS (user 'foreign_username', password 'foreign_password');

您需要在datarestore上创建架构。这是创建新外国表的地方。

CREATE SCHEMA schema_where_foreign_tables_will_be_created;

这将登录到远程主机并在datarestore上创建外部表,指向datastore处的表。只有这样的表才能完成。 不会复制任何数据,只会复制表格。

IMPORT FOREIGN SCHEMA foreign_datastore_schema_name_goes_here
  FROM SERVER foreign_datastore INTO schema_where_foreign_tables_will_be_created;

这将返回此表的数据记录数据库中缺少的id列表

SELECT id FROM foreign_datastore_schema_name_goes_here.table_a
EXCEPT
SELECT id FROM datarestore_schema.table_a

您可以将它们存储在临时表中CREATE TABLE table_a_missing_pk AS [query from above here] 或者马上使用它们:

INSERT INTO datarestore_schema.table_a (id, did, sensorid, timestamp, data, db_timestamp)
SELECT id, did, sensorid, timestamp, data, db_timestamp
  FROM foreign_datastore_schema_name_goes_here.table_a
 WHERE id = ANY((
   SELECT array_agg(id)
     FROM (
       SELECT id FROM foreign_datastore_schema_name_goes_here.table_a
       EXCEPT
       SELECT id FROM datarestore_schema.table_a
     ) sub
  )::int[])

从我的测试中,这应该是下推(意味着发送到远程主机)类似的东西:

Remote SQL: SELECT id, did, sensorid, timestamp, data, db_timestamp
FROM foreign_datastore_schema_name_goes_here.table_a WHERE ((id = ANY ($1::integer[])))

您可以通过在完整查询上运行explain verbose来确保它能够执行,以查看它将执行的计划。你应该在那里看到Remote SQL

如果它不能按预期工作,您可以改为创建临时表,如前所述,并确保此临时表位于datastore主机上。

替代方法是在datastore上创建指向datarestore的外部服务器,并将数据从旧数据库推送到新数据库(可以插入到外部表中)。这样您就不必担心id的列表没有被推到datastore,而是取出所有数据并在之后过滤它们(这将非常慢)。