PostgreSQL 使用 UUID 与文本作为主键

PostgreSQL using UUID vs Text as primary key

我们当前的 PostgreSQL 数据库使用 GUID 作为主键并将它们存储为文本字段。

我对此的最初反应是,尝试执行任何类型的最小笛卡尔连接都将是索引试图找到所有匹配记录的噩梦。但是,也许我对数据库索引的有限理解在这里是错误的。

我认为我们应该使用 UUID,因为它们存储为 GUID 的二进制表示,而 Text 不是,而且您在 Text 列上获得的索引量是最小的。

改变这些将是一个重要的项目,我想知道这是否值得?

正如@Kevin 所提到的,确定您的确切数据的唯一方法是比较和对比这两种方法,但是根据您的描述,我不明白为什么这会与任何方法不同字符串是 table 中的 主键 或唯一索引的一部分的其他情况。

前面可以说的是你的索引可能会更大,因为它们必须存储更大的字符串值,理论上索引的比较会花费更长的时间,但我不提倡过早的优化如果这样做会很痛苦。

根据我的经验,我已经看到在具有数十亿行的 table 上使用 md5sums 的唯一索引的性能非常好。我发现它往往是有关查询的其他因素,这些因素往往会导致性能问题。例如,当您最终需要查询 table 的很大一部分时,比如数十万行,顺序扫描最终是更好的选择,所以这就是查询计划器的选择,而且它可能需要更长的时间。

对于这种情况还有其他缓解策略,例如将查询分块然后 UNION 计算结果(例如,手动模拟将在 HiveImpalaHadoop 领域)。

回复:您对文本索引的担忧,虽然我确信在某些情况下数据集会产生一个密钥分布,以至于它表现得非常糟糕,GUID,就像 md5sums、sha1 等应该很好地索引一般来说,不需要顺序扫描(除非,正如我上面提到的,您查询了大量 table)。

关于索引如何执行的重要因素之一是有多少个唯一值。出于这个原因,具有大量行的 table 上的布尔索引不太可能有帮助,因为它基本上最终会导致任何值发生大量行冲突(是的, false,并且可能为 NULL)在索引中。另一方面,GUID 索引可能有大量没有冲突的值(理论上定义,因为它们是 GUID)。

根据 OP 的评论进行编辑:

So are you saying that a UUID guid is the same thing as a Text guid as far as the indexing goes? Our entire table structure is using Text fields with a guid-like string, but I'm not sure Postgre recognizes it as a Guid. Just a string that happens to be unique.

字面上不一样,不。但是,我是说它们在这种特殊情况下应该具有非常相似的性能,我不明白为什么预先优化是值得做的,特别是考虑到你说这样做是一项非常复杂的任务。

如果在您的特定环境中您 运行 遇到性能问题,您以后可以随时更改。但是,正如我之前提到的,我认为如果遇到这种情况,还有其他方法可能会比更改 PK 数据类型产生更好的性能。

一个UUID is a 128-bit data type (so, 16 bytes), whereas text有1或4个字节的开销加上字符串的实际长度。对于 GUID,这意味着 最小值 为 33 个字节,但根据使用的编码可能会有很大差异。

因此,考虑到这一点,基于文本的 UUID 的索引肯定会更大,因为值更大,并且比较两个字符串与两个数值在理论上效率较低,但不太可能在这种情况下有很大的不同,至少不是通常的情况。

我不会预先优化,因为这样做会产生巨大的成本,而且很可能永远不需要。如果那个时候真的到了,那座桥就可以跨过(尽管我会首先说服其他查询优化,正如我上面提到的)。

关于 Postgres 是否知道该字符串是 GUID,默认情况下肯定不知道。就它而言,它只是一个唯一的字符串。但这对于大多数情况应该没问题,例如匹配行等。如果您发现自己需要一些特别需要 GUID 的行为(例如,一些基于非相等性的比较,其中 GUID 比较可能不同于纯粹的词汇比较),那么您始终可以将字符串转换为 UUID,并且 Postgres 将在该查询期间处理该值。

例如对于文本列 foo,您可以 foo::uuid 将其转换为 uuid.

还有一个模块可用于生成 uuids,uuid-ossp

处理 UUID 数字时,将它们存储为数据类型 uuid总是。 根本没有充分的理由将 text 视为替代方案。无论如何,默认情况下输入和输出是通过文本表示完成的。演员阵容很廉价

数据类型 text 在 RAM 和磁盘上需要更多 space,处理速度较慢且更容易出错。 提供了大部分理由。奇怪的是,他似乎并没有得出相同的结论。

这在之前已经被问过、回答过和讨论过了。相关问题dba.SE 详细解释:

bigint?

也许您根本不需要 UUID (GUID)。请考虑 bigint。它仅占用 8 个字节,并且在各个方面都更快。它的范围经常被低估:

-9223372036854775808 to +9223372036854775807

那是 920 万亿 个正数。 IOW,nine quintillion two hundred twenty-three quadrillion three hundred seventy-two trillion thirty-six something billion.

如果您每秒销毁 100 万个 ID(这是一个非常高的数字),您可以继续这样做 292471 。然后负数又是 292471 年。 "Tens or hundreds of millions" 是 甚至不接近

UUID 实际上只适用于分布式系统和其他特殊情况。