3

我目前有一个 PostgreSQL 数据库,因为我们使用的软件之一只支持这个特定的数据库引擎。然后我有一个查询,它将应用程序中的数据汇总并拆分为更有用的格式。

在我的 MySQL 数据库中,我有一个表,其中包含与上述查询的输出相同的模式。

我想要开发的是一个每小时的cron工作,它将对 PostgreSQL 数据库运行查询,然后将结果插入 MySQL 数据库。在一个小时内,我预计不会看到超过 10,000 行需要传输的新行(这是一个延伸)。

这两个数据库都位于不同的物理服务器上,大洲彼此分开。MySQL 实例在 Amazon RDS 上运行 - 因此我们对机器本身没有太多控制权。PostgreSQL 实例在我们其中一台服务器上的虚拟机上运行,​​让我们可以完全控制。

不幸的是,重复是必要的,因为 PostgreSQL 数据库仅充当信息的收集器,而 MySQL 数据库上运行着一个需要数据的应用程序。为简单起见,我们希望每小时从 PostgreSQL 中进行移动/合并和删除以保持干净。

需要明确的是 - 我是网络/系统管理员 - 不是 DBA。我并不真正了解将一种格式转换为另一种格式所需的所有复杂性。我所知道的是,正在传输的数据由 1x VARCHAR、 1xDATETIME和 6xBIGINT列组成。

我对一种方法的最接近的猜测是使用某种脚本语言进行查询,将结果转换为内部数据结构,然后再次将其拆分回 MySQL。

这样做时,在编写脚本时我应该注意哪些特别好的或坏的做法?或者 - 我应该查看哪些可能对进行这种转换有用的文档?我发现许多调度作业看起来非常易于管理且记录良好,但该脚本的持续性质(每小时运行)似乎不太常见和/或记录较少。

接受任何建议。

4

2 回答 2

3

两端使用相同的数据库系统并使用复制

如果您的远程端也是 PostgreSQL,您可以使用带热备份的流式复制,以透明且自动地保持远程端与本地同步。

如果本地端和远程端都是 MySQL,你可以使用 MySQL 的各种复制功能(如 binlog 复制)做类似的事情。

使用外部脚本同步

使用外部脚本没有任何问题。事实上,即使您使用 DBI-Link 或类似工具(见下文),您也可能必须使用psqlcron 作业中的外部脚本(或 )来启动复制,除非您打算使用PgAgent来执行此操作。

要么在由触发器过程维护的队列表中累积行,要么确保您可以编写始终可靠地仅选择新行的查询。然后连接到目标数据库和INSERT新行。

如果要复制的行太大而无法舒适地放入内存中,您可以使用游标并使用FETCH读取行,如果要复制的行太大而无法舒适地放入内存中,这将很有帮助。

我会按以下顺序完成工作:

  • 连接到 PostgreSQL
  • 连接到 MySQL
  • 开始一个 PostgreSQL 事务
  • 开始一个 MySQL 事务。如果你的 MySQL 正在使用 MyISAM,现在就去修复它。
  • 从 PostgreSQL 读取行,可能通过游标或使用DELETE FROM queue_table RETURNING *
  • 将它们插入 MySQL
  • DELETEPostgreSQL 中队列表中的任何行(如果您还没有的话)。
  • COMMITMySQL 事务。
  • 如果 MySQLCOMMIT成功,COMMIT则 PostgreSQL 事务。如果失败,ROLLBACK则 PostgreSQL 事务并再次尝试整个事情。

PostgreSQLCOMMIT不太可能失败,因为它是一个本地数据库,但如果您需要完美的可靠性,您可以在 PostgreSQL 端使用两阶段提交,您可以:

  • PREPARE TRANSACTION在 PostgreSQL 中
  • COMMIT在 MySQL 中
  • 然后取决于 MySQL 提交的结果COMMIT PREPARED或者在 PostgreSQL 中。ROLLBACK PREPARED

这对于您的需求来说可能太复杂了,但这是完全确定更改发生在两个数据库上的唯一方法,或者两者都不会发生,而不仅仅是一个。

顺便说一句,说真的,如果您的 MySQL 使用MyISAM表存储,您可能应该对此进行补救。它容易在崩溃时丢失数据,并且无法进行事务更新。转换为InnoDB

在 PostgreSQL 中使用 DBI-Link

也许是因为我对 PostgreSQL 很满意,但我会使用一个使用DBI-link via的 PostgreSQL 函数PL/Perlu来完成这项工作。

当应该进行复制时,我会运行一个PL/PgSQL使用PL/PerlDBI-Link 连接到 MySQL 数据库并将数据插入到队列表中的过程。

DBI-Link 的例子很多,这里不再赘述。这是一个常见的用例。

使用触发器对更改进行排队,并使用 DBI-link 进行同步

如果您只想复制新行并且您的表是仅追加的,您可以编写一个触发器过程,将所有新INSERT编辑的行追加到一个与主表具有相同定义的单独队列表中。当您想要同步时,您的同步过程可以在单个事务LOCK TABLE the_queue_table IN EXCLUSIVE MODE;中复制数据,然后DELETE FROM the_queue_table;。这保证不会丢失任何行,尽管它仅适用于INSERT-only 表。在目标表上处理UPDATEDELETE是可能的,但要复杂得多。

使用外部数据包装器将 MySQL 添加到 PostgreSQL

或者,对于 PostgreSQL 9.1 及更高版本,我可能会考虑使用MySQL Foreign Data WrapperODBC FDWJDBC FDW来允许 PostgreSQL 像查看本地表一样查看远程 MySQL 表。然后我可以使用可写的 CTE来复制数据。

WITH moved_rows AS (
    DELETE FROM queue_table RETURNING *
)
INSERT INTO mysql_table
SELECT * FROM moved_rows;
于 2012-09-17T08:42:22.597 回答
0

简而言之,您有两种情况:

1) 使目的地将数据从源中提取到自己的结构中

2)使源将数据从其结构中推送到目标

我宁愿尝试第二个,环顾四周,找到一种方法来创建 postgresql 触发器或一些特殊的“虚拟”表,或者可能是 pl/pgsql 函数 - 然后你将能够执行该过程而不是外部脚本从 cron 或可能从 postgres 内部执行一些查询,有一些操作调度的可能性。我会选择第二种情况,因为 postgres 更加灵活,并且可以通过一些特殊的 DIY 方式来操作数据——您将拥有更多的可能性。

外部脚本可能不是一个好的解决方案,例如因为您需要特别小心地处理二进制数据,或者将日期和时间从 DATE 转换为 VARCHAR,然后再转换为 DATE。在外部脚本中,各种文本存储数据可能只是字符串,您也需要引用它。

于 2012-09-15T13:29:17.073 回答