【问题标题】:Keeping tables synchronized in Oracle在 Oracle 中保持表同步
【发布时间】:2010-11-01 04:59:05
【问题描述】:

我们即将进行并行测试,以将旧系统与新的闪亮版本进行比较。我们有一个 Oracle 数据库表 A,它存储旧系统的数据,以及一个等效的表 B,它存储新系统的数据,因此在测试期间,数据库是非规范化的。 (另外,遗留系统和表 A 是固定的 - 不允许更改)

我想要做的是允许 A 上不常见的 DML 操作传播到 B,反之亦然。我开始使用一对触发器来执行此操作,但遇到了一个明显的问题,即当触发器运行时,表正在发生变化,并引发异常。

是否有处理此问题的标准方法?我已经阅读了关于使用 dbms_scheduler 是否可行的不同报告...

谢谢,

安迪

更新: 我最终退出了整个问题,并确保所有更新 A 的存储过程也更新 B,反之亦然。

我已将 Quassnoi 的回答标记为已接受,因为如果将来遇到同样的问题,我会听从他的建议。

我已经标记了 JosephStyon 的答案,因为我通过在表 A 和 B 上添加两个插入/更新语句级触发器,然后根据哪个触发器使用 A 或 B 作为主表来执行他的合并过程,从而使事情变得简单运行(尽管首先我检查了目标表是否会被合并更改,如果没有则提前退出)。

【问题讨论】:

  • @Andy:如果您的遗留应用程序使用存储过程来更新表,那么看在上帝的份上,只需将您的逻辑放入过程中,因为它应该是这样的。我的建议仅适用于开发不佳的应用程序,它们发出 DML 语句(而不是调用过程)来更新数据。

标签: sql oracle synchronization triggers denormalization


【解决方案1】:

我将在单个规范化(或非规范化)表上创建 AB 作为视图,并在这些视图上创建 INSTEAD OF 触发器以处理 DML 操作。

如果查询计划很重要,最好保留两个表副本:A_underlyingB_underlying,然后像这样创建视图:

CREATE VIEW A
AS
SELECT  *
FROM    A_underlying

CREATE VIEW B
AS
SELECT  *
FROM    B_underlying

谓词将被推送到视图中,实际表和视图的查询计划将是相同的。

在两个视图上的INSTEAD OF 触发器中,您应该将数据放入两个基础表中。

【讨论】:

  • 这实际上是一个非常好的主意。不幸的是,遗留应用程序和数据库模式是固定的。我已经更新了问题以反映这一点。谢谢。
  • 数据库架构对外界保持不变。您甚至可以在另一个模式中创建基础表。通过创建触发器,您更改架构的方式不亚于通过在基础表上创建视图。
  • 真的。更具体地说:我可以在不影响遗留系统的情况下添加触发器。如果我想在单个统一表 AB 上创建视图,我必须修改遗留应用程序以使用它上的视图。
  • @Andy:您可以将旧表 A 重命名为 A_underlying(甚至是 backup_schema.A_underlying)并创建具有相同名称 A 的视图,该视图仅从 A_underlying 中选择所有内容。您的旧版应用程序不会注意到任何内容。
  • 我明白你的意思——很好!不幸的是,我太胆小了,无法做到这一点——遗留系统的代码库非常复杂,以至于它可能会直接插入到表 A 中……如果一切都失败了,我会沿着这条路走。谢谢你:)
【解决方案2】:

您真的是指 DDL,而不是 DML?

使用 DML,您可以查看 Oracles Multi Master Replication 以保持表同步,或者您也可以查看工具 SymmetricDS 来实现此目的。

对于 DDL,我知道的唯一解决方案还是 Oracle advanced replication

【讨论】:

    【解决方案3】:

    将以下三个语句放入存储过程中,然后将其作为计划作业尽可能多地运行:

    --Assume that "A" is a master, and "B" needs to be synched
    
    --If no match in "A", delete from "B"
    DELETE FROM B
    WHERE NOT EXISTS(
                    SELECT *
                    FROM A
                    WHERE A.PRIMARY_KEY = B.PRIMARY_KEY
                    );
    
    --If there is a match, but they are different, then update "B"
    update 
      (
      select
        a.field1 as new_value1
       ,b.field1 as old_value1
       ,a.field2 as new_value2
       ,b.field2 as old_value2
       ,....
       ,a.fieldN as new_valueN
       ,b.fieldN as old_valueN
      from
        a
       ,b
     where a.primary_key = b.primary_key
     )
    set
      old_value1 = new_value1
     ,old_value2 = new_value2
     ,....
     ,old_valueN = new_valueN;
    
    
    --if the record is new to "A", then insert it into "B"
    INSERT INTO B
    SELECT *
    FROM A 
    WHERE NOT EXISTS(
                    SELECT *
                    FROM B 
                    WHERE B.PRIMARY_KEY = A.PRIMARY_KEY
                    );
    

    【讨论】:

    • 你好约瑟夫。表之间没有主/从关系。对 A 的更改应该传播到 B,反之亦然。我想我可以在您的代码中添加一个时间戳来实现这一点,因为更改是用户发起的,并且不太可能出现并发问题。谢谢。
    【解决方案4】:

    Oracle 10g 及更高版本已将更改通知实现为异步过程。它是自动的,并且该软件包包含在 Oracle 10g 及更高版本的服务器安装中。

    您可以查看here 了解一些信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-02
      相关资源
      最近更新 更多