14

我有一个表,它在字段上记录其行插入/更新时间戳。

我想将此表中的数据与另一个数据库服务器上的另一个表同步。两个数据库服务器未连接,同步是一种方式(主/从)。不适合使用表触发器

我的工作流程:

  • 我使用全局 last_sync_date 参数和查询表 Master 来获取更改/插入的记录
  • 将结果行输出到 xml
  • 使用更新和插入解析 xml 和更新表 Slave

处理Master表的已删除记录时,问题的复杂性上升。为了捕捉已删除的记录,我认为我必须为先前插入的记录维护一个日志表并使用 sql“NOT IN”。在处理大型数据集时,这会成为性能问题。

处理这种情况的替代工作流程是什么?

4

10 回答 10

9

听起来您需要一个事务性消息队列。

这是如何工作的很简单。当您更新主数据库时,您可以向消息代理(无论更新是什么)发送一条消息,该消息可以发送到任意数量的队列。每个从属数据库都可以有自己的队列,并且由于队列的保留顺序,进程最终应该正确同步(具有讽刺意味的是,这是大多数 RDBMS 在内部进行复制的方式)。

将消息队列视为一种 SCM 更改列表或补丁列表数据库。也就是说,在大多数情况下,发送到 master 的相同(或大致相同)SQL 语句最终应该被复制到其他数据库。不要担心丢失消息,因为大多数消息队列都支持持久性和事务。

我建议您查看和/或标记了这个问题。

根据您的评论:

  • 请参阅 Spring 集成:http ://static.springsource.org/spring-integration/reference/htmlsingle/ 。
  • 谷歌 SEDA。无论您是否走这条路,您都应该了解消息队列,因为它与批处理密切相关。
  • RabbitMQ 有一个很好的关于消息传递如何工作的图
  • 您的消息内容可能是整行,无论是 CRUD、UPDATE、DELETE。您可以使用任何格式(例如 JSON。请参阅有关建议的 spring 集成)。
    • 您甚至可以将直接 SQL 语句作为消息发送!

顺便说一句,您担心NOT IN成为性能问题并不是一个很好的问题,因为有很多变通方法,但考虑到您不想做特定于数据库的事情(如触发器和复制),我仍然觉得消息队列是您的最佳选择。

编辑 - 非 MQ 路由

由于我让您很难提出这个问题,因此我将继续尝试提供帮助。除了消息队列之外,您还可以像我们之前尝试的那样执行某种 XML 文件。您在模式中需要的关键功能是主数据库上的 CREATE TIMESTAMP 列,以便您可以在系统启动并运行时进行批处理(否则您将不得不停止系统)。现在,如果您走这条路线,您将想要SELECT * WHERE CREATE_TIME < ?少于当前时间。基本上,您只能在快照中获取行。

现在在您的其他数据库上删除您要删除行inner joining的 ID 表但使用!=(即您可以使用 JOINS 而不是 slow NOT IN)。幸运的是,您只需要所有idsfor delete 而不需要其他列。其他列您可以使用基于更新时间戳列的增量(用于更新,并创建又名插入)。

于 2013-03-13T01:38:57.237 回答
5

我不确定解决方案。但我希望这些链接可以帮助你。

http://knowledgebase.apexsql.com/2007/09/how-to-synchronize-data-between.htm

http://www.codeproject.com/Tips/348386/Copy-Synchronize-Table-Data-between-databases

于 2013-03-05T12:17:12.240 回答
2

为什么不添加一个 TIMESTAMP 列来指示上次更新/插入/删除时间?然后添加一个已删除的列 - 即。将该行标记为已删除,而不是立即实际删除它。导出删除操作后将其删除。

如果您无法更改现有应用程序中的架构使用:

你根本不能使用触发器吗?第二个(“隐藏”)表如何填充每个插入/更新/删除并构成下一个要生成的 xml 导出文件的内容?这是一个常见的概念:历史(或“日志”)表:它将有自己的进度 id 列,可用作导出标记。

于 2013-03-06T00:41:07.867 回答
2

看看Oracle GoldenGate

Oracle GoldenGate 是一个全面的软件包,用于在异构数据环境中实现数据复制。该产品集支持运营和分析企业系统之间的高可用性解决方案、实时数据集成、事务变更数据捕获、数据复制、转换和验证。

对称DS

SymmetricDS 是用于在异构环境中跨网络进行多主数据库复制、过滤同步或转换的开源软件。它支持多个订阅者进行单向或双向异步数据复制。

水仙花复制器

Daffodil Replicator 是一个Java工具,用于各种数据库服务器之间的数据同步、数据迁移和数据备份。

于 2013-03-09T08:30:16.700 回答
1

非常有趣的问题。

在可能的情况下,我有足够的 RAM 来加载主表和从表中的所有 id 来区分它们。

如果主表中的 id 是连续的,您尝试可以在主表中维护一组完整填充的范围(使用所有 id 的范围,没有空格,如 100,101,102,103)。

要查找已删除的 id 而不将它们全部加载到内存中,您可以执行 SQL 查询来计算id >= full_region.start and id <= full_region.end每个已填充区域的记录数。如果查询结果,== (full_region.end - full_region.end) + 1则表示区域中的所有记录都没有被删除。否则 - 将区域分成两部分并对它们进行相同的检查(在很多情况下,只有一侧包含已删除的记录)。

在一定长度的范围(我认为大约 5000)之后,加载所有存在的 id 并使用 Set 检查是否存在会更快。

此外,将所有 id 加载到内存中以用于一批小(10-20 条记录)区域也是有意义的。

于 2013-03-05T22:51:51.947 回答
1

为需要同步的表创建一个历史表(基本上是该表的副本,可能带有一些额外的字段),并在每次在活动表中插入/更新/删除某些内容时插入整行。

编写一个 Spring 批处理作业,根据历史表的额外字段将数据同步到 Slave 机器

希望这可以帮助..

于 2013-03-11T11:08:30.197 回答
1

在当前工作流程中允许删除的潜在选项:

如果触发器限制仅限于跨数据库引用的触发器,则当前工作流程中的一个可能解决方案是在主数据库中创建一个帮助表,以仅存储已删除行的唯一标识符(或任何唯一键使您能够最有效地删除已删除的行)。

这些 id 需要在删除时由您的主表上的触发器插入。

使用与插入/更新相同的机制,在插入和更新之后创建一个任务。正如您在当前工作流程中所述,您可以将帮助表导出到 xml。

此任务将简单地从从表中删除行,然后在任务完成后从您的助手表中删除所有数据。记录任务中的任何错误,以便您可以解决此问题,因为没有审计跟踪。

于 2013-03-11T21:39:31.147 回答
1

如果您的数据库有事务转储日志,只需发送该日志即可。

MySQL 是可能的,PostgreSQL 应该也是可能的。

于 2013-03-17T21:52:47.260 回答
0

我同意另一条评论——这需要使用触发器。我认为另一个表应该保存您的 sql 语句的历史记录。请参阅this answer about using 2008 extended events...然后,您可以获得整个sql,并将结果查询存储在历史表中。如果要将其存储为 mysql 查询或 mssql 查询,由您决定。

于 2013-03-09T01:39:49.197 回答
0

这是我的看法。你真的需要处理这个吗?我假设奴隶是为了报告的目的。所以我要问的问题是它应该是最新的吗?如果数据是一天前的可以吗?你计划每晚刷新一次吗?

如果是这样,请忘记此在线同步过程,下载完整表格;将其发送到 mysql 并批量加载。处理时间可能比您想象的要快得多。

于 2013-03-12T00:51:16.443 回答