3 年前,Chiyana 与我们分享了一篇文章,她在文章中问道:为什么避免 SQL 中的自动增量是一个好主意?,其中描述了使用 UUID 的好处。
这就是为什么今天我想与大家分享关于在分布式配置中使用密钥作为唯一标识符及其对写入性能的影响的分析。
使用有序、不重复、自动递增的整数是关系数据库中定义主键的常见做法。这种类型的密钥之所以成功,是因为它满足了两个最重要的索引要求。
1.它们是唯一的,因此可以被唯一地标识。
2. 它们是有组织的并且可以排序,因此可以有效地进行索引。
当数据库是一个整体实体时,这种类型的键是理想的。然而,一旦我们决定扩展并转向分布式设置(例如基于微服务的系统),这不再是唯一的,这是因为现在多个实体开始生成自动递增的数字。
写入期间对聚集索引的影响
在我们继续讨论自动递增整数作为唯一标识符的替代 阿塞拜疆电报筛选方案之前,让我们尝试了解关系数据库写入新数据时索引如何受到影响。
聚集索引通常以B 树数据结构表示。它们具有多种优点,非常适合用于聚集索引。
数据搜索效率高:B 树的设计使得数据搜索效率高,即使在大型数据集中也是如此。它们使用允许快速遍历数据的分层结构,从而减少查找特定值所需的磁盘 I/O 操作次数。
B 树是平衡的:它们是自平衡数据结构,这意味着即使插入或删除数据,它们也能保持平衡的树结构。这有助于确保树高保持相对恒定,从而提高性能并降低数据无法访问的风险。
B 树支持范围查询:它们可以支持范围查询,这意味着它们可以用来有效地查找属于特定范围内的所有值。这在需要查找特定列的某个值范围内的所有记录的场景中很有用。
大多数情况下,在关系数据库中,每个表只允许有 1 个聚集索引,这是因为数据的物理组织由聚集索引(由建立索引的列,通常是主键)控制。
在MSSQL中,当向表写入数据时,数据库引擎包括逻辑写入和物理写入。逻辑写入是指在缓冲区缓存中的页面上修改数据并将其标记为脏。硬写入是指将脏页从缓冲区缓存写入磁盘。由于逻辑写入不会立即写入磁盘,因此只要记录注定要写入该页面(由聚集索引确定),就可以对缓冲区缓存中的页面进行多次逻辑写入。
数据库引擎必须首先根据聚集索引确定用于存储新数据行的正确页面。为此,它通常在索引上执行二进制搜索以识别正确的页面,一旦识别出页面,它就需要将页面从磁盘读入缓冲区缓存,只有当页面不在缓冲区缓存中时才有必要这样做。
如果聚集索引键满足上面讨论的索引要求,则后续写入将不需要从物理磁盘读取页面,因为在大多数情况下,由于先前的写入在短时间内将其读入缓冲区,因此它们将在缓冲区缓存中可用。
一旦您开始使用未排序的列(在构建期间)作为聚集索引;这意味着表中存储的数据需要额外的工作才能按逻辑顺序排列,这会导致写入性能不佳。
分布式环境中的替代唯一标识符
通用唯一标识符 (UUID)
UUID 是 128 位长的字符串,可以保证空间和时间上的唯一性。它们被广泛用于唯一地标识资源。 UUID 有多个版本,每个版本的格式略有不同。最常用的 UUID 版本是 4。
128 位 UUID-V4 字符串
UUID的详细规范可以参见RFC 4122。
分布式设置中的 UUID 允许唯一性,但它们的写入性能不是很好,原因如下。
UUID 是随机字符串(在大多数版本中),在生成过程中没有特定的顺序。当将它们用作聚集索引列时,必须对它们进行排序和存储。由于它们没有排序(在生成过程中自然是没有排序的),因此需要更多的 I/O 来将它们存储在正确的页面上,这可能会导致大型表的写入性能不佳,并且可能导致索引碎片等问题,因为数据页可能不是连续的顺序。
按字典顺序分类的通用唯一标识符 (ULID)