【问题标题】:How to store uuid as number?如何将uuid存储为数字?
【发布时间】:2012-06-08 13:54:06
【问题描述】:

根据问题的答案UUID performance in MySQL,回答者建议将 UUID 存储为数字而不是字符串。我不太确定如何做到这一点。任何人都可以给我一些建议吗?我的 ruby​​ 代码如何处理这个问题?

【问题讨论】:

  • 只有在使用 UUID 作为主键时才会出现性能问题,因为 UUID 不是非常有效的主键。为什么需要 UUID?您能否保留 UUID 并仅使用自动增量作为主键?
  • @ThomSmith Re "UUID 不是非常有效的主键".. 是否愿意引用一个解释原因的来源?
  • 数据比较大,一般需要比较多的指令来比较。它不是顺序的,所以索引的开销只是有点高。而且,当然,如果您将其存储为字符串而不是 128 位数字,就像 OP 似乎正在做的那样,情况会变得更糟。这不是一个糟糕的密钥,但除非有一些外部原因,否则我不会使用它。
  • 自动增量可能会导致多个共享数据库服务器出现问题 - 通常会导致密钥冲突。 UUID 旨在解决此类问题。如果您不是将 UUID 存储为文本,而是存储为 bin(16),那么您当然有一个数字 UUID。比较二进制比比较文本要快。这是一个讨论这个的网站 - mysql.rjweb.org/doc.php/uuid

标签: mysql uuid


【解决方案1】:

如果我理解正确,您在主列中使用 UUID?人们会说常规(整数)主键会更快,但是还有另一种方法可以使用 MySQL 的阴暗面。事实上,当需要索引时,MySQL 使用二进制比其他任何东西都快。

由于 UUID 是 128 位,并且被写成十六进制,因此加速和存储 UUID 非常容易。

首先,在您的编程语言中删除破折号

110E8400-E29B-11D4-A716-446655440000110E8400E29B11D4A716446655440000

现在是 32 个字符(类似于 MD5 哈希,这也适用)。

由于 MySQL 中的单个 BINARY 大小为 8 位,BINARY(16) 是 UUID 的大小 (8*16 = 128)。

您可以使用以下方式插入:

INSERT INTO Table (FieldBin) VALUES (UNHEX("110E8400E29B11D4A716446655440000"))

并使用以下方式查询:

SELECT HEX(FieldBin) AS FieldBin FROM Table

现在使用您的编程语言,在位置 9、14、19 和 24 处重新插入破折号以匹配您的原始 UUID。如果位置总是不同,您可以将该信息存储在第二个字段中。

完整示例:

CREATE TABLE  `test_table` (
    `field_binary` BINARY( 16 ) NULL ,
    PRIMARY KEY (  `field_binary` )
) ENGINE = INNODB ;

INSERT INTO  `test_table` (
    `field_binary`
)
VALUES (
    UNHEX(  '110E8400E29B11D4A716446655440000' )
);

SELECT HEX(field_binary) AS field_binary FROM `test_table`

如果您想将此技术用于任何十六进制字符串,请始终使用length / 2 作为字段长度。因此,对于 sha512,该字段将为 BINARY (64),因为 sha512 编码的长度为 128 个字符。

【讨论】:

  • @Chamnap 假设您的数据库中有 10 000 行,它们是使用 UNHEX 函数添加的,您想搜索 UUID 110E8400-E29B-11D4-A716-446655440000。只需执行以下操作:SELECT * FROM test_table WHERE field_binary LIKE CONCAT("%", UNHEX('110E8400E29B11D4A716446655440000'), "%")
  • 如果你有时间,你可以阅读这个。关注第 3 点:xaprb.com/blog/2009/02/12/…
  • @Chamnap 是的,你可以这样做,你应该这样做。我只是想证明你是否想在 LIKE 中使用带有 UNHEX 函数的字符 %。你可以做WHERE Field = UNHEX('110E8400E29B11D4A716446655440000')。而不是做WHERE Field = 3或其他什么,当你使用十六进制字符串(搜索,插入,在哪里,更新,删除等)时用UNHEX包装字段,当你想用十六进制包装字段从 MySQL 读取(选择)。
  • @DavidBélanger 你说 MySQL 比 int 索引二进制更快。有什么来源吗?
  • BINARY 类型的措辞令人困惑。 mysql 中的单个“BINARY”的大小为 8 位,这就是 BINARY(16) 起作用的原因(8*16 = 128,UUID 的大小)。它确实 NOT “以 1 位存储十六进制在 4 位中的作用”。这不可能。 “每个 BINARY 类型的单元大小可以存储两个十六进制值,它本身大小为 8 位,因此我们需要 16 个单元大小的 BINARY,因此我们将使用 BINARY(16)。”
【解决方案2】:

Percona 博客有一篇文章(包括基准测试)回答了您的问题:Store UUID in an optimized way

【讨论】:

    【解决方案3】:

    我不认为使用二进制文件是个好主意。

    假设您要查询某个值:

    SELECT HEX(field_binary) AS field_binary FROM `test_table`
    

    如果我们返回多个值,那么我们将多次调用 HEX 函数。

    然而,主要的问题是下一个:

    SELECT * FROM `test_table`
        where field_binary=UNHEX('110E8400E29B11D4A716446655440000')
    

    并且在 where 中使用函数,只需忽略索引。

    还有

    SELECT * FROM `test_table`
        where field_binary=x'skdsdfk5rtirfdcv@#*#(&#@$9' 
    

    可能会导致很多问题。

    【讨论】:

    • 您是否测试过您关注的问题的表现?您建议 HEX 和 UNHEX 的性能比使用 36 字符字段作为索引的性能问题更差。我什至不必测试,就知道这是错误的。 (但既然你不相信,那就测试一下)其次,你展示的代码并不是最好的处理方式。您的所有数据库代码都应该只涉及 16 字节字段。不要十六进制和非十六进制。只需将它作为这 16 个字节传入和传出你的数据库。直接使用这些 16 字节值执行所有查询。 只有在向用户展示时,才需要将其转换为用户友好的版本。
    猜你喜欢
    • 2010-10-20
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    • 2014-09-13
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多