【问题标题】:Efficiently and safely assigning unique IDs高效安全地分配唯一 ID
【发布时间】:2013-09-10 11:25:13
【问题描述】:

我正在编写一个数据库,我希望为特定类型的每个项目分配一个唯一 ID(用于内部数据管理)。但是,预计数据库会运行很长时间(理论上无限),并且条目的周转率很高(例如定期删除和添加条目)。

如果我们将我们的唯一 ID 建模为 unsigned int,并假设数据库中的条目总是少于 2^32 - 1(我们不能使用 0 作为唯一 ID),我们可以执行类似的操作以下:

void GenerateUniqueID( Object* pObj )
{
    static unsigned int iCurrUID = 1;
    pObj->SetUniqueID( iCurrUID++ );
}

但是,在开始删除条目并在其位置添加其他条目之前,这很好,可能仍然少于 2^32-1 条目,但我们可能会溢出 iCurrUID 并最终分配已经分配的“唯一”ID正在使用中。

我的一个想法是使用std::bitset<std::numeric_limits<unsigned int>::max-1>,然后遍历它以找到第一个免费的唯一 ID,但这会消耗大量内存并且需要线性复杂度才能找到免费的唯一 ID,所以我寻找更好的方法(如果存在)?

提前致谢!


我知道将数据类型更改为 64 位整数而不是 32 位整数可以解决我的问题;但是,因为我在 Win32 环境中工作,并且使用列表(DWORD_PTR 是 32 位),所以我正在寻找替代解决方案。此外,数据是通过网络发送的,我试图通过使用较小的唯一 ID 来减少带宽消耗。

【问题讨论】:

  • 简单的解决方案是为 id 使用更大的数据类型,如 64 位值,甚至更大(如 IPv6 将地址转换为 128 位值,而 IPv4 为 32 位)。
  • 我同意 Joachim Pileborg 的观点,但我很好奇……所有这些项目都存在于堆中吗?或者他们被保存到磁盘?如果是这样 - 将它们存储在基于文件系统而不是二进制文件中(就像 sqllite 那样)可能是一个更好的主意,并在将它们“平衡”到正确的文件夹结构之后使用它来更快地解决它们,并通过制作 id几乎没用,因为文件路径是您的唯一 ID。哦,您需要处理的所有基础知识(平衡树/清理)让我想知道为什么有人想从头开始编写数据库
  • 并且不回收任何ID
  • 鉴于每秒有这么多项目,磁盘子系统可能无法跟上“条目的高周转率”,因为它们会转化为潜在的大量随机访问。

标签: c++ database performance unique


【解决方案1】:

使用 uint64_t(64 位),即使您每秒插入接近 100k 个条目,它也会花费您超过 100 年的时间。 超过 100 年,您应该插入大约 315,360,000,000,000 条记录(不考虑闰年和闰秒等)。这个数字将适合 49 位。

您预计该应用程序会运行多长时间? 超过 100 年?

当数据库管理员拥有一个接近 32 位限制的自动增量字段时,这是他们经常做的事情。他们将值更改为他们的数据库系统的本机 64 位类型(或 128 位)。

【讨论】:

    【解决方案2】:

    真正的问题是你可以有多少条目,直到你 保证第一个被删除。以及你多久 创建新条目。 unsigned long long 保证 最大值至少为 2^64,约 1.8x10^19。即使在 每微秒创建一个,这将持续几个 千百年。实际上,您将无法 快速创建条目(因为磁盘速度不允许), 你的程序不会运行数百个世纪 (因为硬件不会持续那么久)。如果唯一 id 的 对于基于磁盘的东西,您可以安全地使用 unsigned long long 作为 id。

    否则,当然,生成尽可能多的位 可能需要。如果你真的很偏执,使用它是微不足道的 256 位无符号整数,甚至更长。在某一点, 即使宇宙中的每个原子都创造了一个新的,你也会没事的 每皮秒进入一次,直到宇宙的尽头。 (但 实际上...unsigned long long 就足够了。)

    【讨论】:

      猜你喜欢
      • 2023-03-13
      • 2015-10-05
      • 2016-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多