我目前正在开发一种系统,在某些情况下需要在白天在本地数据库上运行,然后在夜间复制到中央服务器。它不能全部从一个中央数据库运行,因为本地站点定期与它没有联系。中央服务器上的数据仅用于总部的查看和报告,因此无需将任何内容反向复制回网站。
每个“网站”都有一个基于文本的唯一密钥(人工生成)。但是,将数据库设计中的每个表引用为站点键的想法并不吸引人。
以下是一个非常简化版本的架构的示例,其中担心远程复制(对大多数客户端都可以正常工作): -
(我只会显示Area表的历史表,以保持简短):
[Site]
SiteKey [PK] (Gauranteed 100% unique across all sites text based key)
[User]
SiteKey [FK -> Site]
UserID [PK]
[Area]
SiteKey [FK -> Site]
AreaID [PK]
Description
UpdatedDtm
UpdatedUserID [FK -> User]
[AreaHistory]
Site [FK -> Site]
AreaID [FK -> Area]
Description
UpdatedDtm
UpdatedUserID [FK -> User]
AuditedDtm
[Location]
AreaID [FK -> Area]
LocationID [PK]
Description
UpdatedDtm
UpdatedUserID [FK -> User]
[Sensor]
LocationID [PK / FK -> Location]
SensorNo [PK]
UpdatedDtm
UpdatedUserID [FK -> User]
[Reading]
LocationID [PK / FK -> Sensor]
SensorNo [PK / FK -> Sensor]
ReadingDtm [PK]
这很好,直到我将数据库与中央服务器上的数据库“合并”。我显然会在Location表中发生冲突,因为我将数据与其他站点生成的ID混合在一起。
我想到这个问题的第一种方法就是这样做:
短片):
[Location]
SiteKey [FK -> Location, FK -> User] ** ADDED THIS
AreaID [FK -> Area]
LocationID [PK]
Description
UpdatedDtm
UpdatedUserID [FK -> User]
[Sensor]
SiteKey [FK -> Location, FK -> User] ** ADDED THIS
LocationID [PK / FK -> Location]
SensorNo [PK]
UpdatedDtm
UpdatedUserID [FK -> User]
[Reading]
SiteKey [FK -> Sensor] ** ADDED THIS
LocationID [PK / FK -> Sensor]
SensorNo [PK / FK -> Sensor]
ReadingDtm [PK]
基本上,每个表都有一个SiteKey,使每一行都对该站点唯一。
另一种选择(在某些地方使用UUID): -
[User]
SiteKey [FK -> Site]
UserUUID [PK]
[Area]
SiteKey [FK -> Site]
AreaUUID [PK]
Description
UpdatedDtm
UpdatedUserUUID [FK -> User]
[AreaHistory]
Site [FK -> Site]
AreaUUID [FK -> Area]
Description
UpdatedDtm
UpdatedUserUUID [FK -> User]
AuditedDtm
[Location]
AreaUUID [FK -> Area]
LocationUUID [PK]
Description
UpdatedDtm
UpdatedUserUUID [FK -> User]
[Sensor]
LocationUUID [PK / FK -> Location]
SensorNo [PK]
UpdatedDtm
UpdatedUserUUID [FK -> User]
[Reading]
LocationUUID [PK / FK -> Sensor]
SensorNo [PK / FK -> Sensor]
ReadingDtm [PK]
请记住这是减少的,但它说明了问题。
我可能会遗漏任何其他选择吗?我想过ID重新映射,但这似乎引入了更糟糕的恶梦。
令人讨厌的部分是,使用这种情况的情况非常少,其余部分对一个服务于许多网站的数据库感到满意。但是,想要这种情况的客户是最大的; - )
我想也许我可以只为他们使用UUID,但这意味着在任何地方创建异常,所以如果我要使用它们,也可以在整个过程中使用它们(必要时)。
如果它有任何区别,我正在使用PostgreSQL。
PS,this讨论可能与此案有关。我只是想知道是否有另一种方式考虑我有一个很好的gauranteed独特的SiteKey。
答案 0 :(得分:2)
我或多或少得出结论,恕我直言,对于这种情况,使用UUID是一个“快速修复”,甚至可能有点黑客攻击。我决定对我来说,在这种情况下,使用复合键更清洁。使用UUID,我也可以将SiteKey预先渲染到每个ID。
答案 1 :(得分:1)
大多数复制方案都需要使用GUID / UUID。我会在每张桌子上加一个。阅读有关使用one的性能影响以及如何在特定数据库后端中最好地避免它们的内容。
答案 2 :(得分:1)
我还会添加您可能想要至少考虑的另一套开箱即用的答案:
如果要将站点作为基础数据中复合键的一部分 - 使用代码生成,视图和可更新触发器(至少在SQL Server上),可以创建可更新的视图没有暴露网站密钥。因此,您可以将其隐藏在应用程序层中(这假设应用程序不会是站点感知的)。
不要真正复制,而是将数据合并到报告数据库中,并且只将网站放在报告层。当然你的架构是不同的,但它是用于报告的,所以它甚至需要相同的RI吗?
您的报告数据库不仅必须具有相同的模式,它还可以具有完全不同的非规范化模式,如针对专业报告需求而优化的数据仓库。
答案 3 :(得分:0)
鉴于你所说的,我会使用GUID(随着表数的增加,更偏向于此)。请注意,在SQL Server中,因为将聚簇索引放在一个狭窄的增加键上是很好的,并且通常这也是主键,因此通用GUID不那么有效,因为它会导致与非增加性相关的问题。有一个NEWSEQUENTIALID()只生成顺序GUID:
INT vs Unique-Identifier for ID field in database
我使用COMB ID技术之前还能够从GUID中提取日期时间,为您提供免费的创建时间戳(虽然不一定是免费的,因为它本身不能真正自行索引)(从那以后)你已经为GUID和int获取额外的字节了)
我假设某些或大部分逻辑适用于postgressql,但就其索引或集群/堆实现的具体情况而言,我没有直接经验。