对于我们新的MySQL数据库,我们正在考虑使用
UUID
作为存储为BINARY(16)
的主键。键值将由 Java 应用程序中的以下函数生成,或者由 UUID_TO_BIN(UUID())
数据加载中的内置函数等生成。
UUID.randomUUID();
public static byte[] convertUUIDToBytes(UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
}
public static UUID convertBytesToUUID(byte[] bytes) {
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
long high = byteBuffer.getLong();
long low = byteBuffer.getLong();
return new UUID(high, low);
}
SYS_GUID()
在 Oracle 中生成完全随机数,通常用作一级主键或唯一键,但许多博客声称使用 UUID Ver 4 会因为它的非顺序性质而出现严重的性能问题MySQL 网站上的博客.
使用 UUID Ver 4 检索数据会不会有任何性能问题。我们的数据在插入顺序方面是完全随机的,我们的查询访问最先插入的行的机会与访问最近插入的行的机会相同。而且我们不希望查询结果中的行按插入顺序显示。我们也不需要查询以主键值作为范围的行。
插入行时会不会有任何性能问题。
我们确实知道,与 UUID 作为键相比,数字会具有更好的性能,但 UUID 是我们数据的重要组成部分,大多数查询将使用 UUID 作为键。
使用UUID时存在性能差异和存储大小差异。差异是否大到足以使它成为您应用程序的交易破坏者是您必须自己测试的东西。
Percona 在这个主题上写了一些很棒的博客。
使用 UUID 还是不使用 UUID?(2007)
对于 auto_increment 键加载过程需要 1 小时 50 分钟,加载速度为 40305 行/秒。对于 UUID 过程花费了 12 多个小时并且仍在进行中。从 MySQL 状态我可以看到它正在加载大约 200 行/秒并且它仍然随着关键文件的增长而减慢一点。所以在这个小案例中我们有大约 200 倍的性能差异值得考虑
说明 InnoDB 中的主键模型及其对磁盘使用的影响(2015)
...下图向我们展示了 UUID() 会导致严重的碎片化,因为它会导致页面在整个表中被拆分。这被认为是“昂贵的”,因为 ibd 文件现在比 UUID() 优化的方法大 2 倍以上,比使用 AUTO_INCREMENT 的主键大大约 3 倍。
水平轴 – 刀片数 x 25,000
纵轴 - 以秒为单位的时间
我会避免使用 UUID 作为主键除非您将数据存储在多个 MySQL 实例中(即分片)并且您需要确保它们在所有实例中保持唯一。
不要打扰 V6.
MySQL 8 的
UUID_TO_BIN()
做 V6 做的事情,但是在从十六进制转换为二进制时进行。也就是说,如果您在使用该功能后存储在BINARY(16)
中,则不需要V6来获取参考位置。
MariaDB 10.7 同样为 UUID 添加了一个成熟的“数据类型”。它显示 V1,但将位混洗为 16 字节的二进制数据类型。
我的讨论,十几年前的:http://mysql.rjweb.org/doc.php/uuid
(感谢 V6 的链接;我会把它添加到我的博客中。)
发现一个谷歌文档提倡反对使用单调递增的键。本文档是关于 NoSQL 数据库的,但有些部分适用于存储在单个节点上的数据。
https://cloud.google.com/datastore/docs/best-practices
如果您将自己的手动数字 ID 或自定义名称分配给 您创建的实体,不要使用单调递增的值,例如 如:1、2、3、……、
不要索引单调递增的属性 值(例如 NOW() 时间戳)。维护这样的索引可以 导致影响应用数据存储模式延迟的热点 具有高读写率。
我的问题实际上与 UUID 无关:使用单调增长的键值与随机数相比的含义。我希望知道任何差异的原因。根据我的理解,传入的行按照插入的顺序附加到数据文件中,而不管键值是什么以及指向这些行的指针添加到索引中。向索引中添加键会产生这样的差异吗?我认为无论数据是否排序,MySQL DB 用于索引的 B-Tree(或其某些变体)的插入复杂性或多或少是相同的。