合并两个表,重复键

时间:2012-05-16 14:25:11

标签: sql-server performance indexing primary-key

*我对此非常陌生,我可能(可能会?)偶尔会说一些乱语,随时纠正我;)

我正在玩不同的主键/索引策略,并且想知道以下内容。在许多情况下,选择GUID作为主键是在任何数据库中为记录提供唯一标识。

现在使用GUID作为主键(以及将其用作聚簇索引的默认行为)存在一些性能问题。可以想到一些替代方案,例如使用NEWSEQUENTIALID()或添加额外的IDENTITY列来提供顺序聚簇索引。

另一个是在主键(和索引)中一起取消GUID,同时在全球范围内提供一个唯一标识列,一个外部标识符/ rowid。 这会留下较小的表格。当然,附加列有16字节的惩罚,但是在具有少量FK的表中很快被分解。页面上有更多的东西,不错的顺序ID,更小的索引空间,所以赢得胜利。

然而,这种方法给我们带来了一个令人讨厌的缺点:当你想要合并2个表时,你会遇到重复的键。现在,我不是在提倡这种方法,我只是在探索和比较不同的策略,以使我更熟悉这部分数据库设计。

问题是:在这种情况下,我们如何使用GUID的唯一性来处理重复的密钥问题?是否应该禁用所有表约束并在表合并时生成IDENTITY?这种方法应该完全放弃吗?

2 个答案:

答案 0 :(得分:4)

我认为你根本不需要GUID。虽然NEWSEQUENTIALID()在页面拆分方面比NEWID()更好,但在大多数情况下它仍然是一个比必要更宽的密钥,而你失去 GUID的唯一其他好处(你可以生成它们)提前 - 你不能用NEWSEQUENTIALID())。然而,您仍然存在与IDENTITY值类似的热点问题,其中所有插入活动都在相同的范围内发生。那么它真正获得了什么?

我已经实现了一些替代方法,以避免需要跨系统维护唯一键值的多实例系统中的GUID。


身份范围

如果要在多个服务器中生成标识值,并且稍后需要合并它们,请使用标识范围(具有足够大的边距以进行增长)。在服务器一:

CREATE TABLE dbo.Data
(
  ID BIGINT IDENTITY(1000000000, 1) PRIMARY KEY
);

在服务器2上:

CREATE TABLE dbo.Data
(
  ID BIGINT IDENTITY(2000000000, 1) PRIMARY KEY
);

您可以使用INT,具体取决于您认为您将使用多少值 - 但最好提前计划并留下大量空间,而不是稍后更改它。除非您生成大量数据,否则几个世纪以来您不必担心碰撞。

密钥大小:8个字节。 (如果可以使用INT,还是4个字节。)


复合键

另一种方法是在表上只有一个ServerID列,并将其作为复合键的一部分。只要您不打算扩展到超过255台服务器,就可以使用TINYINT(1字节)。在服务器一:

CREATE TABLE dbo.Data
(
  ServerID TINYINT NOT NULL DEFAULT 1,
  DataID INT IDENTITY(1,1),
  PRIMARY KEY (ServerID, DataID)
);

在服务器2上:

CREATE TABLE dbo.Data
(
  ServerID TINYINT NOT NULL DEFAULT 2,
  DataID INT IDENTITY(1,1),
  PRIMARY KEY (ServerID, DataID)
);

现在你只需要在合并系统上的FK中携带两列(或在合并中创建一个IDENTITY列)......对于连接来说有点痛苦,但是比携带GUID要轻得多。

密钥大小:5个字节。 (或者6个字节,如果你需要升级到SMALLINT,因为255个服务器还不够。)

答案 1 :(得分:0)

出于好奇,合并的目的是什么?

就个人而言,我会采取身份认同的态度。如果聚集索引是标识值,那么在合并期间设置标识插入将起作用,假设该ID只是为行提供唯一值,并且不是任何FK所必需的(不会扰乱您的数据完整性) )。新行只会在表中以新ID结束而不会出现任何冲突问题

这取决于您的使用案例,但除非必要,否则我倾向于远离GUID