符合delta同步的数据库模式

时间:2011-01-13 20:03:51

标签: mysql database synchronization schema delta

这只是一个需要讨论的问题。 现在,我需要重新设计一个mysql数据库表。基本上,此表包含我从另一个数据库同步的所有合同记录。合同记录可以修改,删除或用户可以通过GUI界面添加新的合同记录。在此阶段,表结构与合同信息(列:序列号,到期日期等)完全相同。在这种情况下,我只能同步整个表(删除所有旧记录,替换为新记录)。如果我想要delta(只与已修改的,新的,已删除的记录同步)同步表,我该如何更改数据库模式?

这是我提出的方法,但我需要你的建议,因为我认为这是数据库应用程序中的常见场景。 1)引入序列号概念/列:对于每个序列,用该序列号标记新添加的记录,修改的记录,删除的记录。通过记录最后一个同步的序列号,只传递那些序列号较高的记录;

2)因为可以添加已删除的合同,并且原始表具有主键约束,是否应该为这些已删除的记录创建另一个表?或添加一个标志列以指示该合同是否已被删除?

我希望我能清楚地解释我的问题。无论如何,如果你知道任何文章或你自己的建议,请告诉我。谢谢!

1 个答案:

答案 0 :(得分:8)

我认为你对三角洲的概念感到困惑。

您可以收到满载(整个数据集)或仅收到更改(“delta”)。

如果你处理满载,你可以进行截断+插入。这样您就不必处理新旧行或删除行。由于参照完整性约束等,这可能是不可行的。

如果您收到增量,则每行通常会分为两类:

  1. 匹配键= UPDATE。您可以选择忽略具有相同数据或覆盖的行。
  2. 没有匹配的键= INSERT
  3. 删除很特别。不存在的行无法发送给您。因此,您需要就如何处理它达成一致。如果是满载,则可以删除接收数据集中不存在的所有本地行。

    如果是delta,您可以同意使用删除标记(标记,日期)发送行。然后,您可以决定是否使用删除标记保留行(由上面的(1)自动处理),或者您应该DELETE行。我建议保留它,因为迟早有人会指责你丢失行/数据质量差,然后你就把DELETE_DATE扔掉了。

    对于MySQL,您可以使用INSERT ... ON DUPLICATE KEY UPDATE来实现“upsert”功能。

    如果您需要更具体的帮助,则必须提供更多详细信息。

    <强>更新

    好的,这是一个例子。假设您有以下表结构:

    create table contracts(
       contract_id int         not null
      ,details1    varchar(20)
      ,details2    varchar(20)
      ,delete_date date
      ,primary key(contract_id)
    );
    

    每当收到更新的行时,都会将它们插入到具有相同结构的临时表中:

    create table contracts_delta(
       contract_id int         not null
      ,details1    varchar(20)
      ,details2    varchar(20)
      ,delete_date date
      ,primary key(contract_id)
    );
    

    一些示例数据:

    mysql> select * from contracts;
    +-------------+----------+----------+-------------+
    | contract_id | details1 | details2 | delete_date |
    +-------------+----------+----------+-------------+
    |           1 | a1       | a2       | NULL        |
    |           2 | b1       | b2       | NULL        |
    |           3 | c1       | c2       | 2011-01-03  |
    +-------------+----------+----------+-------------+
    
    mysql> select * from contracts_delta;
    +-------------+----------+----------+-------------+
    | contract_id | details1 | details2 | delete_date |
    +-------------+----------+----------+-------------+
    |           2 | b1       | b2       | 2011-01-03  | <-- Row was deleted
    |           3 | c1       | c2       | NULL        | <-- No longer deleted
    |           4 | d1       | d2       | NULL        | <-- This is new row
    +-------------+----------+----------+-------------+
    

    使用我之前链接的语法,您可以插入所有新行。每当行已经存在(重复)时,我们选择更新列。请注意,这会自动处理已删除的行,因为delete_date是与其他所有内容一样的常规列。

    insert 
      into contracts(
            contract_id
           ,details1
           ,details2
           ,delete_date
           )
     select contract_id
           ,details1
           ,details2
           ,delete_date
      from contracts_delta s
        on duplicate key 
        update contracts.details1    = s.details1
              ,contracts.details2    = s.details2
              ,contracts.delete_date = s.delete_date;
    

    在“upsert”之后,合同中的数据将如下所示:

    mysql> select * from contracts;
    +-------------+----------+----------+-------------+
    | contract_id | details1 | details2 | delete_date |
    +-------------+----------+----------+-------------+
    |           1 | a1       | a2       | NULL        |
    |           2 | b1       | b2       | 2011-01-03  |
    |           3 | c1       | c2       | NULL        |
    |           4 | d1       | d2       | NULL        |
    +-------------+----------+----------+-------------+
    

    - 此时您可以选择删除增量表(请记住下次重新创建它)

    drop table contracts_delta;
    

    - 或者您可以截断它以节省一些空间。 (无论如何,你需要确保它在下次加载时是空的)

    truncate table contracts_delta;
    

    - 或者你可以保存实际的delta(重命名表格),以便你有时需要单独的增量

    alter table contracts_delta rename to contracts_delta_20110115;