用户的唯一标识符

7
如果我有一个包含一百个用户的表格,通常我会设置一个自增的userID列作为主键。但是如果突然有一百万或五百万个用户,那么这将变得非常困难,因为我希望开始更加分布式,这种情况下自增主键将毫无用处,因为每个节点都会创建相同的主键。
解决方案是使用自然主键吗?我很难想出这些用户的自然主键。问题在于他们都是年轻人,所以他们没有国民保险号码或任何其他我能想到的唯一标识符。我可以创建一个多列主键,但仍有可能发生重复,尽管可能性微乎其微。
有人知道解决方案吗?
谢谢
9个回答

11

我认为目前最好保留用户ID的自增功能。

如果未来某时出现了数百万用户的突然激增,那么再考虑修改。 换句话说,解决问题应该在问题出现后再进行,因为“过早地优化是万恶之源”。

回答这个问题-一些自增功能可以允许你种子自增,这样你就可以在不同的节点上获得不同的自增值。 这将避免问题的发生,同时仍然允许使用自增功能。


7
虽然我和任何人一样反对过早或不必要的优化,但我更加反对在使用中的表上更改主键。 - Adam Robinson
@Adam Robinson - 我完全同意。然而,我们也需要对某些问题的出现保持现实态度。 - Oded
我同意Adam的观点。如果我认为Christopher永远不会遇到身份字段问题,我可能会投票反对Oded。 - user287466

8

这里的标准解决方案是使用GUID。但是从索引的角度来看,它们的性能不如其他方法。


2
正如你可能知道的那样,你可以通过用日期时间替换GUID的一半或四分之一来牺牲一些GUID的唯一性。我相信这被称为COMB GUID。索引性能接近于整数。也就是说,GUID将在页面中占用更多的空间并导致更多的分割。 - Thomas
1
当你达到500万用户时,难道不需要尽可能提高性能吗?在这个表上浪费缓存内存索引长GUID和许多外键将会是一种浪费。 - KM.

2

如果您需要数百万个ID并且有许多节点,请将主键设置为以下内容的组合:

NodeID  int   --unique for each node 2 or 4 byte  
UserID  int   --auto increment 8 byte, repeats for each node

这比GUID更好(更小,占用更少的内存,并且更快)。


2

GUID是不错的选择,但存在碰撞风险(尽管很少发生)。

这可能是一种非标准解决方案,但我想提出:

您可以使用自增数字,但根据将来的分发进行数字空间隔离。

假设您有3个服务器,请按以下方式记录ID:

服务器1:0-9,999,999
服务器2:10,000,000-19,999,999
服务器3:20,000,000-29,999,999

即使在32位整数的限制下,这应该还留有足够的扩展空间(如果您担心也可以使用100,000,000的间隔),并且它基本上保证了系统的唯一性。


1

除非你想要糟糕的性能和潜在的不良数据,否则永远不要使用自然主键。几乎没有什么自然键是不会随时间而改变的,尤其是名称。如果自然键发生变化,则所有相关的子记录也必须更改。这显然是不好的。

您可以使用 GUID。但是,在数据方面,500万只是微不足道的数字,可能不需要进行更改。我们的系统中有超过1000万个不同的人员,我们只有一个中等大小的数据库,没有分区或需要GUID。


0

GUID是一种简单的方法,但...

它需要分布到多远?如果只有有限数量的数据库,您可以为每个数据库分配一定范围的数字。例如,第一个数据库自动生成0到999,999范围内的数字,下一个使用1,000,000到1,999,999。这样,它们可以生成用户ID而不会相互干扰。如果数据库包括唯一的标识号码,则可以从该号码自动生成范围。

我认为您不能使用自动递增列来完成此操作,但存储过程可以以这种方式生成数字。


0

当集群时,GUID作为键是垃圾。如果非集群,则仍需要在另一列上创建聚集索引。

使用整数键,并为每个new节点/站点

  • 以10的步长递增。随着添加节点,只需从2、3等开始
  • 使用范围,例如1-> 1000000,1000000 -> 1999999等
  • 不要忘记-ve。例如,您可以为第二个节点设置IDENTITY(-1,-1)

如果您确实有节点/站点,则第二列带有SiteID也可以工作。


1
当然,那些点踩的人都知道GUID更优秀了吧? - gbn

0
如果您正在使用MSSQL,您可以将表的PK创建为UNIQUEIDENTIFIER,并将默认值或绑定设置为NEWID()。

0

我建议您永远不要考虑使用GUID,原因是我目前正在遇到一些问题。假设您有数百万个用户,则可能需要更大的并发度,并且GUID将在插入和删除时破坏您的生活,因为您将在它们上面拥有索引,并且默认情况下它将是一个聚集索引,这意味着每次插入和删除都会物理移动记录。此外,GUID不是连续的,因此每个新插入都有可能出现在页面底部或顶部,因此整体插入和删除操作将变得非常昂贵,如果您删除索引,则选择操作将变得昂贵。

特别是如果您有多个表格并且它们之间存在关系,请勿将GUID视为主键。

以下是我推荐的两种解决方案。

  1. 如果您可以创建复合键,那将是完美的,比如说如果它是银行软件,那么branchId、transactionId可能会成为主键,其中branchId是插入记录的节点的标识,而transactionId是分支上的自动编号,这样您就可以获得全程唯一性。

  2. 如果以上不是您想要做或考虑的内容,那么您可以使用Guid作为唯一字段,但添加一个自增数字作为主键,这将帮助您降低整体成本,例如当客户端(节点)使用(Web服务)RPC发送数据时,您必须将记录插入服务器数据库,然后将生成一个自动编号,此自动编号可用于未来的选择、删除或更新,但客户端不必知道此自动编号。

我知道第二种解决方案有点令人困惑和复杂,但它仍然比使用Guids作为PK好。但如果适用于解决方案1,请选择它。

当我说成本时,不仅是处理时间,还包括锁定(等待)时间,这完全是浪费金钱,您的四核服务器可能只执行了一半,更多的锁意味着更多的死锁机会,所以我的朋友永远不要使用Guids。

敬礼 Mubashar


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接