【问题标题】:Unique identifiers for users用户的唯一标识符
【发布时间】:2023-03-22 19:40:02
【问题描述】:

如果我通常有一个包含一百个用户的表,我只会设置一个自动递增的 userID 列作为主键。但是,如果突然我们有 100 万或 500 万用户,那将变得非常困难,因为我希望开始变得更加分布式,在这种情况下,自动增量主键将毫无用处,因为每个节点都将创建相同的主键。

解决方案是使用自然主键吗?我很难为这群用户考虑一个自然的主键。问题是他们都是年轻人,所以他们没有国家保险号码或我能想到的任何其他唯一标识符。我可以创建一个多列主键,但仍然有机会,但发生的重复很少。

有人知道解决办法吗?

谢谢

【问题讨论】:

    标签: sql primary-key natural-key


    【解决方案1】:

    这里的标准解决方案是使用 GUID。不过,它们在索引方面的表现不会那么好。

    【讨论】:

    • 您可能知道,您可以通过将 GUID 的一半或四分之一替换为 DateTime 来牺牲一些 GUID 的唯一性。我相信这被称为 COMB guid。索引性能非常接近 int。也就是说,GUID 会占用页面中的更多空间并导致更多拆分。
    • 当您达到 500 万用户时,您是否不需要获得所有性能?您将浪费缓存内存索引此表上的长 GUID 和许多 FK。
    【解决方案2】:

    我会说暂时保持用户 ID 的自动递增。

    当您突然涌入数百万用户时,您可以考虑改变它。

    换句话说,当你遇到问题时解决它。 “过早的优化是万恶之源。”

    回答这个问题 - 一些自动增量将允许您播种自动增量,因此您可以在不同节点上获得不同的自动增量。这将避免该问题,同时仍允许使用自动增量。

    【讨论】:

    • 虽然我反对过早/不必要的优化,但我更多反对更改正在使用的表上的主键。
    • @Adam Robinson - 我完全同意。然而,人们也需要对即将出现的某些问题保持现实。
    • 我同意亚当的观点。如果我认为 Christopher 会遇到身份字段问题,我可能会投票给 Oded。
    【解决方案3】:

    切勿使用自然主键,除非您想要糟糕的性能和潜在的不良数据。很少有自然键会随着时间而变化,尤其是名称。如果自然键更改,则所有相关子记录也必须更改。这显然很糟糕。

    您可以使用 GUIDS。但 500 万在数据方面不算什么,可能不需要改变。我们的系统中有超过 10,000,000 名不同的人,我们只有一个中型数据库,没有分区,也不需要 GUID。

    【讨论】:

      【解决方案4】:

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

      它需要分布到何种程度?如果是有限数量的数据库,您可以为每个数据库指定一个可使用的数字范围。例如,第一个数据库自动生成 0 到 999,999 范围内的数字,下一个使用 1,000,000 到 1,999,999。这样他们就可以各自生成一个用户 ID,而不会相互碰撞。如果数据库包含一个唯一的数字来识别它,那么范围可以从这个数字自动生成。

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

      【讨论】:

        【解决方案5】:

        GUID 很好,但容易发生冲突(尽管很少见)。

        这可能是一个非标准的解决方案,但我会把它扔在那里:

        您可以使用自动递增的数字,但将来根据分布分隔数字空间。

        假设您有 3 台服务器。记录ID如下:

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

        即使在 32 位 int 的约束下,也应该留下足够的扩展空间(如果您担心的话,甚至可以使用 100,000,000 的间隙),并且它基本上保证了整个系统的唯一性。

        【讨论】:

          【解决方案6】:

          GUID 在集群时作为键是垃圾。如果是非聚集索引,您仍然需要在另一列上使用聚集索引。

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

          • 以 10 为增量递增。添加节点时,只需从 2、3 等开始
          • 使用范围,例如 1-> 1000000、1000000 -> 1999999 等
          • 别忘了-ve。例如,您可以为第二个节点设置 IDENTITY (-1,-1)

          如果您确实有节点/站点,那么带有 SiteID 的第二列也可以使用。

          【讨论】:

          • 当然,反对者知道所有关于 GUID 的优越性......?
          【解决方案7】:

          如果您需要数百万个 ID 并且有许多节点,请将主键组合为:

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

          这比 GUID 好得多(更小,使用更少的内存,并且会更快)

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

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

              特别是如果您有多个表并且它们之间存在关系,则不要将 Guids 视为主键。

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

                1234563分支,因此您将一路获得唯一性。
              1. 如果上面不是您喜欢做或考虑的,那么您可以使用 Guid 作为唯一字段,但添加一个自动增量编号作为主键,这将帮助您降低总成本,例如当客户端(节点) 使用(Web 服务)RPC 发送数据,然后您必须将记录插入服务器数据库,然后将生成一个自动编号,此自动编号可用于将来的选择、删除或更新,但客户端不必知道此自动编号

              我知道第二种解决方案有点混乱和复杂,但它仍然比使用 Guid 作为 PK 更好。但如果解决方案 1 适用,那就去吧。

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

              问候 穆巴沙尔

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-11-08
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-10-06
                • 1970-01-01
                相关资源
                最近更新 更多