【问题标题】:Sequential UID set generation for MySQL Char() or other FieldMySQL Char() 或其他字段的顺序 UID 集生成
【发布时间】:2011-05-10 21:41:06
【问题描述】:

试过谷歌搜索但是:

问题: 为 MySQL 字段外部生成 Sequential UID 值的最佳方法,该字段必须可以表示为字符串。

原因:
从 char[0] 向前搜索字段索引时,磁盘顺序/页面附加插入的通用顺序 UUID 值用于写入性能和读取速度的日期前缀。该列将被索引,但会寻找最佳数据以提高索引读取和表写入性能,而不是普通的旧 UUID。

我最初的想法是在固定宽度的字符字段中附加或替换 UUIDv4 生成的字符串的某些部分(即[Unix epoch][remaining UUID4])以某种粒度(可能是填充的纪元)的日期,但我不确定这是否会满足所需-page/disk 排序结果和索引搜索结果。一个例子是:

12904645950049bceba1cc24e80806dd

这些值必须独立于 MySQL 本身,因此使用 UUID 和时间戳,而不是自动递增的某些变体。

任何了解 MySQL 索引内部的人有什么建议(对于 InnoDB 表)?

艾登

【问题讨论】:

  • 调整数据结构以提高性能通常会敲响我的警钟。你确定你问的是正确的问题吗?内部结构(例如预读策略)往往会随着版本的变化而变化,并使您的优化变得无用。如果您的更新是突发的,那么当您最需要它时,时代可能会回来困扰您。我会专注于使用 innodb 诊断工具来了解真正的瓶颈在哪里,并通过数据库参数化而不是更改数据模型来解决它们。
  • 更多的是已知的普通 UUID 会对索引等造成过度压力......所以寻找轻微的 UUID 修改。如果我能杀死两只鸟,能够对 UUID 进行日期排序也是一个好处......

标签: mysql indexing uuid


【解决方案1】:

可能有点离题,但请查看Twitter's snowflake。他们说是:

  • (大致)按时间排序(有助于避免昂贵的随机主键 BTREE 更新)
  • 可直接排序
  • 紧凑

更不用说其他功能(HA 等)。您可以修改他们的算法,也可以直接使用它。

整个 UID 最多只使用 64 位空间,所以我猜想索引会非常有效 - 请参阅 http://www.mysqlperformanceblog.com/2006/10/03/long-primary-key-for-innodb-tables/(反例)。

【讨论】:

  • MySQL 中内置的 UUID() 也可以生成具有类似功能的 ID。我不是提问者,但我认为他的兴趣在于专门利用指数内部行为的 ID。有许多现有的 UUID 生成解决方案,但没有关于它如何影响索引质量的信息,我怀疑将它们中的任何一个链接到这个特定问题是否有价值。
  • Twitter 的雪花很有趣;然而显眼的编译器(很棒​​的显示名称)是对的,我的主要观点是类似 UUID 的 PK 和索引列的读/写性能。
  • 你也可以看看这个:mysqlha.blogspot.com/2010/11/…
【解决方案2】:

我认为您可能需要更具体地说明您要解决的问题(实际问题是什么 - 为什么不是 auto_increment?,您建议的架构是什么?等等)。 要回答您的内部问题:

  • InnoDB 将数据存储在 16K 页的索引(聚集索引)中。

不按顺序插入的风险至少有两个:

  1. 如果您的内存不足,您可能需要执行随机 IO 以从磁盘加载页面以将值插入该页面。

  2. 页面中可能没有剩余空间(InnoDB 填充了 93% 并留有小间隙用于更新),这可能导致页面需要拆分。更多的拆分页面 = 碎片化/内存等事物的最佳使用。

所以,我认为只要您是近似顺序的,至少 (1) 不是主键索引的问题(对于任何唯一索引仍然可能如此)。您只需要担心 (2)。


我之所以说理解问题很重要,是因为除了长 GUID 之外,还有很多方法可以做到这一点。一方面,MySQL 中的 BIGINT 比您可能使用的任何数据类型都小,但范围为 18 quintillion。您可以一次将 N 千个密钥空间的“块”分配给工作节点,并保证没有重复。如果一个工作节点崩溃并且没有使用它分配的所有块,那又怎样。没关系。

【讨论】:

【解决方案3】:

看看这个question。它可能没有详细说明 MySQL 索引的具体用途,但它确实为您提供了一些性能数据以及生成 Seq 的代码。 UID。

似乎 MySQL 索引从顺序 ID 中受益匪浅,并且根据 MySQL 的说法,索引依赖于磁盘排序(参见章节:B-Tree 索引特征)来查找相关结果。

从内存中,MySQL 索引(至少对于字符串索引)首先依赖于字段的字母数字顺序,即“哦,它以 A 开头?我有以 A 开头的数据,我会获取它给你……等等。”而不是对每个字段进行全文扫描。

按顺序输入 UID 意味着索引不会首先“按字母顺序”重新排​​序结果,或者至少大大减少了这一时间,因此上述性能优势。

(不是真正的解决方案,但至少是一个答案。)

【讨论】:

    【解决方案4】:

    我所做的是使用固定宽度的字符字段并将随机 UUID 字符串附加到当前时间(以毫秒为单位)。这很好,因为即使您的服务器在同一毫秒内被访问两次,它仍然(可能)是唯一的。我假设如果您有 大量 服务器负载,这可能会提供多个 id,但如果担心您可以检查是否已经创建了具有此 uuid 的行。

    PHP:

    $date = new DateTime();
    $UUID = uniqid( $date->format('Uu'), FALSE);  // For less length
    $UUID = uniqid( $date->format('Uu'), TRUE);   // For more length
    

    这是我在(很少使用的)服务器上使用的。但它应该能承受更大的负载。正如我所说,要克服创建两个相同密钥的微小机会,请检查它是否已被使用并分配一个新密钥。 (这不应该经常发生)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-21
      • 2023-02-18
      • 1970-01-01
      • 1970-01-01
      • 2014-05-16
      • 2020-08-09
      • 1970-01-01
      相关资源
      最近更新 更多