0

问题

如何避免客户端/服务器数据库中的主键冲突

背景

我正在同步多个数据库。我有一个中央 SQL Server 数据库和许多客户端 SQL Server 数据库。现在说我在数据库中有一个表 X,它有一个主键 ID。

在第一个客户端中,我们在表 X 中有以下 ID:

X(客户端 1)
--------
1|SomeValue
2|SomeValue
3|SomeValue
4|SomeValue

在第二个客户中,我有

X(客户端 2)
--------
1|SomeValue
2|SomeValue
3|SomeValue
4|SomeValue

当我同步时,我希望客户端只上传他们的数据而不是下载它们。

现在,当我将第一个客户端与服务器同步时,它将添加来自 (1 .. 4) 的主键。但是,当我与第二个客户端同步时,会出现 PRIMARY KEY CLASH。我怎么解决这个问题?

我正在使用 SQL Server 2008 R2、同步框架和 C#。

我已经考虑过使用 GUID 作为主键的想法,这在我的情况下是不可行的,因为我正在处理旧数据库。此外,重新播种 IDENTITY 值的想法有点容易出错。如何在不插入值的情况下增加标识列?PS:主键设置为 IDENTITY,增量为 1。

4

3 回答 3

5

为了支持能够插入记录的分布式客户端,模式必须支持客户端数据库创建没有冲突的行。这意味着要么使用 PK 的 GUID,要么使用串联的密钥。(ID + ClientID) *无论哪种方式,架构更改。

否则,手动同步客户端数据库意味着要么在插入之前检查冲突的 ID,要么处理异常然后替换 ID,或者允许为冲突的记录生成身份。这意味着更新所有 FK 关系。耗时且容易出错。

于 2013-01-05T15:17:23.657 回答
2

有几种方法可以做到这一点。第一个是是否有保证唯一键,上游和下游数据库都可以通过该键来引用该记录。在 SQL Server 的情况下,您想要的密钥类型是 UNIQUEIDENTIFIER(又名 GUID)。

现在,如果由于某种原因您不能使用 UNIQUEIDENTIFIER,那么第二好的选择是为位置或类似的东西添加一个额外的列。此列将标识记录来自的单个数据库。例如,第一个客户端的位置 ID 可能为 1,第二个客户端的位置 ID 为 2,依此类推。然后,您可以将现有主键修改为该位置 ID 和当前 ID 的复合键。

第三种选择是根本不修改客户端数据库,而仅将位置 ID 列添加到“主”数据库中的表中。如果您在代码中手动同步,则代码需要考虑记录的来源并酌情添加 id。这可能很困难,但肯定是可能的。

除非您必须重新设定客户端数据库的种子,才能在特定点启动它们的身份值。例如,客户端 1 可能会获得 1 到 10000 的值,客户端 2 可能会获得 10001 到 20000 的值。但是,您可以在此处看到失败的可能性。不仅如果客户端超出了您允许的范围,而且如果您设置了其他客户端并且有人搞砸了种子值。此外,修复所有现有客户将是一个完整的 PITA。


附带说明一下,在构建您知道将有一个需要合并的分布式数据库的应用程序时,简单地使用 GUID 作为主键几乎是普遍的明智之举。是的,它会分割索引等,但在这种情况下,这些缺点比完整的 PITA 更可取,并且当您最终将所有这些数据合并在一起时可能发生的错误。

于 2013-01-05T16:46:38.270 回答
0

除了@Chris 的第三个选项,如果您使用的是 Sync Framework,您实际上可以“欺骗”它为服务器端 PK 添加一个额外的列。

请参阅:第 1 部分 – 客户端和服务器主键不同的上传同步

于 2013-01-06T02:56:51.880 回答