用于“巨大”数据库表PK的顺序GUID或bigint


14

我知道这类问题很多,但是我还没有阅读任何有说服力的论点来帮助我做出这个决定。请多多包涵!

我有一个庞大的数据库-它每天增长大约10,000,000条记录。数据是关系数据,出于性能原因,我将表与BULK COPY一起加载。因此,我需要为行生成键,并且不能依赖IDENTITY列。

64位整数(bigint)足够我使用,但是为了保证唯一性,我需要一个集中生成器来为我创建ID。我目前有这样的生成器服务,该服务允许服务保留X序列号并保证不发生冲突。但是,这样做的结果是,我拥有的所有服务都依赖于该集中式生成器,因此我在分配系统方面受到限制,并且对施加的其他依赖项(例如要求网络访问)不满意通过这种设计。有时这是一个问题。

我现在正在考虑使用顺序GUID作为主键(在SQL外部生成)。从我自己的测试中可以确定的是,这些操作的唯一缺点是较宽数据类型的磁盘空间开销(索引中使用它们会加剧这种情况)。与bigint相比,我还没有看到查询性能的任何明显下降。使用“批量复制”加载表的速度稍慢,但幅度不大。得益于我的顺序GUID实现,基于GUID的索引不会变得零散。

基本上,我想知道的是,是否还有我可能忽略的其他注意事项。目前,我倾向于飞跃并开始使用GUID。我绝不是数据库专家,所以我非常感谢任何指导。


2
您将如何生成“顺序GUID”?

这是一个自定义实现。它基本上是一种GUID类型的格式,用6个字节替换为时间戳字节,用2个字节表示时间戳相同的序列号。它不能保证产生完美的顺序值,但足以使索引碎片对我来说不是问题。

因此,您是从多个不同的来源加载此数据吗?我还假设您担心碎片化的索引是聚集索引吗?

2
如果要使用顺序GUID,则应查看NEWSEQUENTIALID()。它应该做您想要的(单调递增),并且不依赖于自定义代码。

2
看看Jeremiah Peschka在“密钥的麻烦 ”一文中的内容。读得很好,他已经多次处理了这些实现。
billinkc

Answers:


4

我也有类似的情况。当前,我正在使用顺序GUID方法,并且没有碎片并且易于生成密钥。

我注意到了两个导致我开始迁移到bigint的缺点:

  1. 空间使用情况。每个索引多8个字节。将其乘以10个索引左右,您将浪费大量空间。
  2. 列存储索引不支持GUID。

(2)是我的杀手.。

我现在将生成这样的密钥:

yyMMddHH1234567890

我将使用前置日期加小时,之后再使用顺序部分。这使我可以按日期对数据进行范围查询,而根本没有任何附加索引。对我来说这是一个不错的奖励。

我将使用HiLo算法生成bigint的顺序部分,该算法很适合于分发

希望这能转移到您的情况。我绝对建议使用bigint。


1
将其标记为“答案”,因为它是最合适的(您似乎很欣赏我要问的内容,以及为什么它不像初次出现时那么简单)。我想我将使用共享序列生成器(它将与您的HiLo算法建议类似地工作)。我正在其他问题上解决这个问题,我只需要忍受额外的依赖。那好吧。谢谢。
Barguast

3

使用type INT从1开始,您将获得20亿以上的行-对于绝大多数情况而言,这已经足够了。有了BIGINT,您大约可以得到922万亿次(922个有15个零-92,000万亿个),足以满足您的需要?

如果使用1 INT IDENTITY开头,并且每秒插入一行,则需要66.5 才能达到20亿的限制...。

如果您使用1 BIGINT IDENTITY开头,并且每秒插入一千行,那么您需要惊人的2.92亿年才能达到922万亿次极限...。

每天使用1000万行,您将有足够的数量来存储大约1'844'674'407'370天(18440 亿天或超过50亿年的滴答)的数据-足够满足您的需求?

MSDN联机丛书中阅读有关它的更多信息(包括所有选项)。


1
每天1000万行的插入率将在200天内耗尽INT范围。
mceda

@mceda:是的-我还有其他要求吗?它并不会BIGINT很快耗尽范围,但是....
marc_s 2012年

谢谢,但是正如我在问题中说的那样,在将ID发送到数据库之前,我需要ID。数据是关系数据,因此在批量复制之前,我需要分配主键和外键。如果不是那样,那么身份标识可能是完美的。

2
@Barguast:难道不能只是将数据批量插入到临时表中(没有身份),然后使用从那里将其移动到实际数据表中BIGINT IDENTITY吗?
marc_s 2012年

@marc_s:是的,提供的计算与以下问题不符:“如果使用从1开始的INT IDENTITY,并且每秒插入一行,则需要66.5年才能达到20亿的限制”。
mceda

2

我建议您在SQL 2012中使用BIGINT数据类型的SEQUENCE。与IDENTITY相比,它具有诸如cache / nocache之类的选项更加灵活,您还可以为批处理操作指定一个序列范围sp_sequence_get_range。


不幸的是,SQL Azure不支持SEQUENCE。
蒂莫西·李·罗素

2

是因为正在加载的单独表之间已经存在外键关系,所以无法使用IDENTITY的原因?而且,您没有其他自然钥匙可以将它们从暂存区到生产区的操作中链接起来吗?因此,在批量复制之前,我想了解更多有关它们在源系统中如何“链接”的信息。当多个源系统放入共享数据库时,它们是否仅使用它们自己的序列并有可能发生序列冲突?

COMB ID /顺序GUID技术是我熟悉的一种技术,并且在您有效地需要在数据库外部分配全局唯一性的任何时候都可以使用-它实际上是数据库内部和外部的可用行标识。因此,在高度分散的环境或不连贯的情况下,这是一个不错的选择

除非您真的不需要它,否则因为当数据大小增加并且这些键位于每个索引和许多查询的工作集中时,额外的宽度差异就很明显。

此外,在分布式生成的情况下,如果行实际上不是按GUID列的顺序排列,则与在IDENTITY上进行聚簇相比,将其用于聚簇索引键(窄,静态,递增)的问题可能会导致某些碎片化保持。


0

通常,可以使用command OUTPUT子句INSERT将数据插入到两个表中并与标识字段相关。

基于时间戳的标识符不应被认为是可靠的-它取决于系统时钟,而系统时钟又取决于许多因素-从硬件时钟到时间同步服务。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.