使用字符串类型和UUID类型作为UUID主键的性能影响有多大?

15

如果主键使用字符串string,与实际的uuid类型相比,在索引查找方面是否存在很大的速度差异,特别是如果字符串具有前缀,如user-94a942de-05d3-481c-9e0c-da319eb69206(使查找必须遍历5-6个字符才能到达唯一的内容)?


1
我认为,两个长度略微不同的字符串索引之间的速度差异微不足道。如果您真的在意,那么请向您的表中添加自动增量/序列列,并使用整数作为索引。 - Gordon Linoff
2
可能是PostgreSQL UUID类型性能的重复问题。 - Schwern
@GordonLinoff 在MySQL中,UUIDs只是字符串。而在PostgreSQL中,它们被存储为数字。 - Schwern
@Schwern 正在提出一个不同但相关的问题。 - Steve
@Steve 啊。嗯...据我所知,MySQL没有UUID类型,而且我不确定为什么你不使用PostgreSQL的UUID类型。你能解释一下为什么吗? - Schwern
显示剩余2条评论
3个回答

26
这是一种微优化,直到你达到巨大规模,它不太可能引起真正的性能问题。使用最适合你设计的键。话虽如此,以下是详细信息...
UUID是内置的PostgreSQL类型。它基本上是一个128位整数。它应该像任何其他大整数一样作为索引执行。从Postgres 13开始,它提供了gen_random_uuid()函数来生成UUIDv4(基本上只是一个随机数)。要获取更多函数,你可以加载uuid-ossp扩展,或者你可以在客户端生成UUID。在客户端生成UUID可以将额外的工作(并不多)分散到服务器之外。
MySQL没有内置的UUID类型。相反,有一个UUID()可以生成一个UUIDv1作为十六进制数字的字符串。因为它是一个字符串,UUID键可能会对性能和存储造成影响。它还可能干扰复制。您可以使用UUID_TO_BIN()将其转换为varbinary(16);实际上是一个128位整数。
字符串UUID会更长;每个字节的十六进制字符只编码4位数据,因此一个十六进制字符串UUID需要256位来存储128位的信息。这意味着每列需要更多的存储和内存,可能会影响性能。
通常情况下,这意味着比较的长度会是原来的两倍,因为被比较的键的长度是原来的两倍。然而,UUID通常在前几个字节中是唯一的,所以不需要比较整个UUID就可以知道它们是不同的。长话短说:在真实应用中,比较字符串和二进制UUID不应该导致明显的性能差异...尽管MySQL的UUID是UTF8编码的这个事实可能会增加一些成本。
在PostgreSQL上使用UUID是可以的,它是一个内置类型。
MySQL的UUID键的实现意味着你需要在字符串和varbinary之间进行大量的转换,这容易引入错误,并且使用UUIDv1会有一些轻微的安全隐患。

1
UUID的字符串版本通常有4个破折号,因此使用CHAR(36) - Rick James
5
PostgreSQL 13引入了gen_random_uuid()函数,以避免安装uuid-ossp模块仅仅为了获取随机的(v4)UUID。尽管该模块仍然可用于获取其他版本或函数。 - GreenReaper

7
UUID的真正问题在于当表格(或至少是索引)太大而无法缓存到内存中时。当这种情况发生时,“下一个”uuid需要存储到(或从)一些“随机”的块中,这些块不太可能被缓存。随着表格的增长,这导致了越来越多的I/O。
自增ID通常不会遭受I/O增长的问题,因为插入总是在表格的“末尾”,选择通常靠近末尾。这导致了高效地使用缓存,从而避免了I/O死亡。
我的UUID博客讨论了如何使“Type-1” UUID对MySQL的性能影响更小。

0

使用内置的UUID类型,它映射到128位整数。这不仅是为了提高性能,还可以防止像“password1”这样的字符串出现在该列中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接