什么是 UUID,它们为什么有用? – CloudSavvy 计算
网络代理 » 数字新闻 » 什么是 UUID,它们为什么有用? – CloudSavvy 计算

什么是 UUID,它们为什么有用? – CloudSavvy 计算

通用唯一标识符 (UUID) 是一种特定形式的标识符,在大多数实际用途中可以安全地认为是唯一的。 两个正确生成的 UUID 相同的可能性几乎可以忽略不计,即使它们是由不同的各方在两个不同的环境中创建的。 这就是为什么说 UUID 普遍地 独特。

在本文中,我们将了解 UUID 的特性、它们的唯一性是如何工作的,以及它们可以简化资源识别的场景。 尽管我们从与数据库记录交互的软件的共同角度来处理 UUID,但它们广泛适用于需要分散生成唯一标识符的任何用例。

什么是 UUID?

UUID 只是一个您可以安全地视为唯一的值。 碰撞的风险是如此之低,以至于您可以合理地选择完全忽略它。 您可能会看到使用不同术语引用的 UUID(GUID 或 Globally Unique Identifier,是 Microsoft 的首选语义),但含义和效果保持不变。

真正的 UUID 是由标准化格式生成和表示的唯一标识符。 有效的 UUID 由 RFC 4122 定义; 本规范描述了可用于生成 UUID 的算法,这些 UUID 在实现之间保持唯一性,而无需中央发行机构。

RFC 包括五种不同的算法,每种算法使用不同的机制来产生值。 以下是可用“版本”的简要摘要:

  • 版本 1 – 基于时间 – 结合时间戳、时钟序列和特定于始发设备的值(通常是其 MAC 地址),以在该确切时间为该主机生成唯一的输出。
  • 版本 2 – DCE 安全 – 该版本是作为版本 1 的演进版本开发的,用于分布式计算环境 (DCE)。 它没有被广泛使用。
  • 版本 3 – 基于名称 (MD5) – MD5 散列一个“命名空间”和一个“名称”,以在命名空间中为该名称创建一个唯一值。 生成另一个具有相同命名空间和名称的 UUID 将产生相同的输出,因此此方法提供可重现的结果。
  • 版本 4 – 随机 – 大多数现代系统倾向于使用 UUID v4,因为它使用主机的随机或伪随机数源来发出其值。 两次生成相同 UUID 的机会几乎可以忽略不计。
  • 版本 5 – 基于名称 (SHA-1) – 这类似于版本 3,但它使用更强大的 SHA-1 算法来散列命名空间和条目名称。

尽管 RFC 将算法称为版本,但这并不意味着您应该始终使用版本 5,因为它显然是最新的。 选择哪一个取决于您的用例; 在许多情况下,选择 v4 是因为它的随机性。 这使它成为简单的“给我一个新的登录”场景的完美候选者。

生成算法发出一个 128 位无符号整数。 但是,UUID 通常被认为是十六进制字符串,也可以存储为 16 个字符的二进制序列。 这是一个示例 UUID 字符串:

16763be4-6022-406e-a950-fcd5018633ca

该值由五组由短划线分隔的字母数字字符表示。 破折号不是字符串的必需组件; 它们的存在是由于 UUID 规范的历史细节。 它们还使标识符更容易被人眼感知。

UUID 用例

UUID 的主要用例是去中心化生成唯一标识符。 您可以在任何地方生成 UUID 并安全地认为它是唯一的,无论它来自您的后端代码、客户端设备还是您的数据库引擎。

UUID 简化了在断开连接的环境中确定和维护对象的身份。 从历史上看,大多数应用程序使用自动递增的整数字段作为主键。 当你创建一个新对象时,你无法知道它的 ID,直到 它已被插入到数据库中。 UUID 允许您在应用程序中更早地确定身份。

这是一个演示差异的基本 PHP 演示。 我们先来看基于整数的系统:

 博客文章 {
    公开 功能 __构造(
        公开 只读?int $ id,
        公开 只读字符串 $头条,
        公开 readonly?AuthorCollection $作者=) {}
}
 
#[POST("/posts")]
功能 创建博客帖子(请求 $请求) : 无效 {
    $标题 = $请求 -> 获取字段(“头条新闻”);
    $blogPost =  博客文章(, $标题);
}

我们需要初始化 $Id 财产与 null 因为我们无法知道它的真实身份,直到 它已保存在数据库中。 这并不理想—— $Id 不应该真的可以为空,这允许 BlogPost 实例以不完整的状态存在。

切换到 UUID 可以解决问题:

 博客文章 {
    公开 功能 __构造(
        公开 只读字符串 $uid,
        公开 只读字符串 $头条,
        公开 readonly?AuthorCollection $作者=) {}
}
 
#[POST("/posts")]
功能 创建博客帖子(请求 $请求) : 无效 {
    $标题 = $请求 -> 获取字段(“头条新闻”);
    $blogPost =  博客文章(“16763be4-……”, $标题);
}

现在可以在应用内生成帖子 ID,而不会出现重复值的风险。 这可确保对象实例始终表示有效状态,并且不需要笨拙的可为空 ID 属性。 该模型还有助于事务逻辑的管理; 需要引用其父级的子记录(例如我们的帖子 Author 关联)可以立即插入,而无需返回数据库来检索分配给父级的 ID。

将来,您的博客应用程序可能会将更多逻辑移至客户端。 也许前端支持创建完整的离线草稿,从而创建 BlogPost 临时存储在用户设备上的实例。 现在客户端可以生成帖子的 UUID 并在网络连接恢复时将其传递给服务器。 如果客户端稍后从服务器检索草稿副本,它可以将其与任何剩余的本地状态匹配,因为 UUID 已经是已知的。

UUID 还可以帮助您组合来自各种来源的数据。 使用整数键合并数据库表和缓存可能很乏味且容易出错。 UUID 不仅在表内提供唯一性,而且在整个宇宙中提供唯一性。 这使它们成为经常在不同存储系统之间移动的复制结构和数据的更好候选者。

UUID 遇到数据库时的注意事项

UUID 的好处非常引人注目。 但是,在实际系统中使用它们时需要注意几个陷阱。 支持整数标识符的一个重要因素是它们易于扩展和优化。 数据库引擎可以轻松地索引、排序和过滤仅在一个方向上的数字列表。

UUID 不能这样说。 首先,UUID 比整数大四倍(36 字节对 4 字节); 对于大型数据集,这本身可能是一个重要的考虑因素。 值的排序和索引也更加棘手,尤其是在更常见的随机 UUID 的情况下。 它们的随机性意味着它们没有自然顺序。 如果您使用 UUID 作为主键,它将损害索引性能。

在大量使用外键的规范化数据库中,这些问题可能会更加复杂。 现在您可以拥有许多关系表,每个表都包含对您的 36 字节 UUID 的引用。 最后,执行连接和排序所需的额外内存可能会对系统性能产生重大影响。

您可以通过将 UUID 存储为二进制数据来部分缓解这些问题。 这意味着一个 BINARY(16) 列而不是 VARCHAR(36). 一些数据库,如 PostgreSQL,包括 UUID 数据类型; 其他像 MySQL 的函数可以将 UUID 字符串转换为其二进制表示,反之亦然。 这种方法效率更高,但请记住,您仍将使用其他资源来存储和选择数据。

一种有效的策略可能是将整数保留为主键,但添加一个额外的 UUID 字段以供应用程序参考。 当您的代码检索和插入具有 UUID 的顶级对象时,关系链接表可以使用 ID 来提高性能。 这一切都取决于您的系统、规模和优先级:当您需要去中心化 ID 生成和简单的数据融合时,UUID 是最佳选择,但您必须认识到权衡。

总结

UUID 是您可以安全地用于去中心化身份生成的唯一值。 碰撞 可能,但应该非常罕见,以至于可以排除它们。 如果您在整个世纪内每秒生成 50 亿个 UUID,假设有足够的熵可用,遇到重复的概率约为 XNUMX%。

在插入发生之前,您可以使用 UUID 建立独立于数据库的身份。 这简化了应用程序级代码并防止错误识别的对象存在于您的系统中。 UUID 还通过确保数据存储、设备或环境的唯一性来促进数据复制,这与在表级别操作的传统整数键不同。

尽管 UUID 现在在软件开发中无处不在,但它们并不是一个完美的解决方案。 新手倾向于关注冲突的可能性,但这不应该是您的主要关注点,除非您的系统非常敏感以至于需要保证唯一性。

对于大多数开发人员来说,最明显的挑战是存储和检索生成的 UUID。 天真地使用 VARCHAR(36) (或通过删除连字符并使用 VARCHAR(32)) 可能会随着时间的推移削弱您的应用程序,因为大多数数据库索引优化将无效。 寻找您的数据库系统的内置 UUID 管理功能,以确保您从解决方案中获得最佳性能。

★★★★★