提案:本地唯一的GUID替代方案

时间:2017-05-29 21:26:43

标签: indexing primary-key collision guid identifier

问题

我正在寻找关于本地唯一的GUID替代的探索的反馈,具有以下要求:

  1. 碰撞的可能性非常低(我们每年要碰撞一次而不是执行检查)
  2. 不会泄露敏感信息,例如存在多少项
  3. 在SQL数据库中具有高性能
  4. 是否可以复制/管理手动查询(作为查询字符串和查询结果)
  5. 可用作不带编码的URI组件
  6. 为了满足要求,我决定采用 64位无符号整数的形式。它很容易在CPU上使用,对于主键使用很好和很小,半人类可读,仅数字,并且在手动查询时易于复制/粘贴。 (作为反例,BLOB严重阻碍了对大多数SQL数据库的手动查询。)

    此外,Percona demonstrates 单调增加值作为主键表现得更好,特别是在插入速度方面,因此这是一个目标特征。

    建议的结构

    从左到右,最重要的位在左侧

    1. 46位。的时间戳即可。 Unix时间,以毫秒为单位。 (至少在C#中,亚毫秒时间并不容易获得。)这将持续到4199年的某个地方。它给我们单调递增的值。
    2. 8位。 本地IP的一部分。机器内部IP地址的最后一个组件,是最快的可用网络接口。大多数服务器应该是以太网LAN。
    3. 10位。的 Uniquefier 即可。一个静态计数器,在使用时递增(互锁),带有环绕。
    4. 碰撞

      在任何时候都有1/1024(~0.1%)的碰撞机会:

      1. 两个系统共享相同的最后一个IP地址组件以相同的毫秒进行呼叫。 这可以完全避免。
      2. 系统的时钟被转回并且它在时间变化之前的同一毫秒的呼叫中进行呼叫。 这应该是一种非常罕见的情况,似乎符合要求。
      3. 限制

        有趣的是,我们似乎满足了要求(#2是一个狡猾的要求)。让我们来看看一些限制。

        1. 服务器'必须仔细维护本地IP地址 - 即使在不同的数据中心之间也是如此(如果适用)。
        2. 如果存在对IP的其他限制,我们不能支持超过255台服务器 - 可能更少。
        3. 我们泄漏有关哪个标识符由同一服务器创建的信息。我相信这也是许多GUID实现的情况。
        4. 通过检查用户自己的请求之间的计数器增量,可以获得有关流量的信息。由于计数器用于各种数据,迅速增加并且难以归因于任何特定类型的数据,因此有效性降低。
        5. 标识符比具有大量随机性的标识符更具猜测性。蛮力攻击每次尝试毫秒需要大约512次调用(uniquefier)。理想情况下,这种攻击不产生任何结果,即系统报告"未授权"无论标识符是否不存在或不属于用户,都能抵抗时间攻击。实际上,让我们假设专门的攻击者会发现泄密。
        6. 考虑

          1. 限制#1和#2必须符合公司的要求。

          2. 限制#3似乎在现有的GUID实施中被认为是可接受的,并且是我愿意接受的。

          3. 限制#4是一个棘手的问题。这些信息有多敏感? "因此我们每分钟进行10K插入,进入未知数量的表格。"相对数量确实提供了更多的洞察力:"在08:00-09:00之间,活动的时间是一小时前的两倍。"不过,这通常是特定领域的常识。意外的峰值可能会泄漏更多信息。 "因此系统在早上03:00努力工作。"这有多糟糕?从公开自动增量标识符的公司数量来看,我们可能会说它经常是一种改进......但它可能是一个交易破坏者。

          4. 我们可以使用(加密)随机位作为处理限制#4的唯一文件,但这会引入第三个碰撞机会:每当系统在一毫秒内生成多个标识符时。生日悖论在那里特别成问题。

          5. 如果我们允许时间戳已经在2527中回绕,我们可以释放2位。自私和对后代不敏感,或傲慢地假设我们的代码会被更长时间使用? : - )

          6. 还有什么?

            我欢迎您错过了我的反馈,改进,想法和限制!你会如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

有可能成为那个回应的人#34;你为什么要那样做?" - 我想知道你的潜在业务问题是什么,阻止你使用GUID?

BIGINT,GUID和HashTables ..

我使用BIGINT作为主键,它可以保持所有顺序,非浮动和快速。这适用于所有内部工作,即在我的存储过程中,在SQL连接等上。然后我有一个带有GUID的哈希表,它成为外部调用者的起点。

由于我使用表继承,BIGINT ID可用作哈希表中的顺序主键,因为所有ID都是在整个数据库中都是唯一的(但仍然是顺序的)。然后进一步研究我在哈希表上创建一个包含GUID的最后几位数字的复合键,然后在这些值上对哈希表进行分区,使每个值分别存储在磁盘上并且仍然是顺序的,然而,我给了我一个自然的方法来索引GUID我正在查找。

当我最初开始这样做时,我在这里发布了一个操作方法(不包括分区部分):

What is the fastest way to look for duplicate uniqueidentifier in Sql Server?

初步的性能测试对100,000,000条记录的反应很快。

不是你问题的答案,但对某人来说可能值2美分。