1

*我对此很陌生,我可能(可能会?)时不时说些胡言乱语,请随时纠正我;)

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

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

另一种方法是完全取消主键(和索引)中的 GUID,同时提供一个用于全球唯一标识的列,即外部标识符/rowid。这给你留下了更小的桌子。当然,附加列有 16 字节的损失,但在有几个 FK 的表中,这很快就会减少。页面上的内容更多,顺序 ID 很好,索引空间更小,所以双赢。

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

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

4

2 回答 2

4

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

以下是我实施的几种替代方法,以避免多实例系统中的 GUID 需要跨系统维护唯一键值。


身份范围

如果您在多个服务器中生成身份值并且稍后需要合并这些值,请使用身份范围(具有足够大的增长余量)。在服务器一上:

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

在服务器二上:

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

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

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


复合键

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

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

在服务器二上:

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 个服务器还不够。)

于 2012-05-16T14:38:02.760 回答
0

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

我个人会采取身份方法。如果聚集索引是一个标识值,那么在合并期间将标识插入设置为 ON 将起作用,假设 ID 只是为行提供唯一值并且任何 FK 都不需要(不会破坏您的数据完整性)。新行将最终出现在具有新 ID 的表中,而不会出现任何冲突问题

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

于 2012-05-16T14:31:59.097 回答