这只是一个需要讨论的问题。 现在,我需要重新设计一个mysql数据库表。基本上,此表包含我从另一个数据库同步的所有合同记录。合同记录可以修改,删除或用户可以通过GUI界面添加新的合同记录。在此阶段,表结构与合同信息(列:序列号,到期日期等)完全相同。在这种情况下,我只能同步整个表(删除所有旧记录,替换为新记录)。如果我想要delta(只与已修改的,新的,已删除的记录同步)同步表,我该如何更改数据库模式?
这是我提出的方法,但我需要你的建议,因为我认为这是数据库应用程序中的常见场景。 1)引入序列号概念/列:对于每个序列,用该序列号标记新添加的记录,修改的记录,删除的记录。通过记录最后一个同步的序列号,只传递那些序列号较高的记录;
2)因为可以添加已删除的合同,并且原始表具有主键约束,是否应该为这些已删除的记录创建另一个表?或添加一个标志列以指示该合同是否已被删除?
我希望我能清楚地解释我的问题。无论如何,如果你知道任何文章或你自己的建议,请告诉我。谢谢!
答案 0 :(得分:8)
我认为你对三角洲的概念感到困惑。
您可以收到满载(整个数据集)或仅收到更改(“delta”)。
如果你处理满载,你可以进行截断+插入。这样您就不必处理新旧行或删除行。由于参照完整性约束等,这可能是不可行的。
如果您收到增量,则每行通常会分为两类:
UPDATE
。您可以选择忽略具有相同数据或覆盖的行。INSERT
删除很特别。不存在的行无法发送给您。因此,您需要就如何处理它达成一致。如果是满载,则可以删除接收数据集中不存在的所有本地行。
如果是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;