PostgreSQL使用UUID vs Text作为主键

时间:2015-11-20 21:58:38

标签: postgresql primary-key uuid

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

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

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

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

2 个答案:

答案 0 :(得分:12)

处理UUID号码时,请将其存储为数据类型 uuid 始终。甚至没有充分理由将text视为替代方案。无论如何,输入和输出默认通过文本表示完成。演员非常便宜。

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

之前已经提出并回答过并进行了讨论。有关dba.SE的相关问题及详细解释:

bigint

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

-9223372036854775808 to +9223372036854775807

那是 9亿,数百万正数。我,nine quintillion two hundred twenty-three quadrillion three hundred seventy-two trillion thirty-six something billion

如果您每秒刻录100万个ID(这是一个非常高的数字),您可以继续这样做292471 。然后另外292471年为负数。 “数十万或数亿”甚至没有关闭

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

答案 1 :(得分:9)

正如@Kevin所提到的,唯一可以确切地了解您的确切数据的方法是比较和对比这两种方法,但是从您所描述的内容来看,我不明白为什么这会有所不同来自任何其他情况,其中字符串是表中的主键或唯一索引的一部分。

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

根据我的经验,我在一个有数十亿行的表上使用md5sums的唯一索引上看到了非常好的性能。我发现它往往是查询的其他因素,往往会导致性能问题。例如,当你最终需要查询表的一个非常大的行,比如数十万行时,顺序扫描最终成为更好的选择,这就是查询计划程序选择的内容,以及它可能需要更长时间。

针对这种情况还有其他缓解策略,例如分块查询然后UNION结果(例如,手动模拟将在 Hive中完成的事情 Hadoop 范围内的em>或 Impala

Re:您对文本索引的关注,而我确定在某些情况下,数据集会产生密钥分发,导致其执行非常糟糕的GUID,就像md5sums,sha1&s;等等。应该在一般情况下编制索引,并且不需要顺序扫描(除非,如上所述,您查询表格的大块区域)。

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

根据OP的评论进行编辑:

字面意思不一样,没有。但是,我说他们应该对这个特殊情况有非常相似的表现,而且我不明白为什么优先预测是值得做的,特别是考虑到你说这样做将是一个非常复杂的任务。

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

UUID是128位数据类型(因此,16个字节),而text有1或4个字节的开销加上字符串的实际长度。对于GUID,这意味着最小为33个字节,但根据使用的编码可能会有很大差异。

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

我不会预先优化这样做会带来很大的成本,而且很可能永远不需要。如果那个时间到来的话,那个桥就可以越过了(虽然我会先讨论其他的查询优化,如上所述)。

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

e.g。对于文本列foo,您可以foo::uuid将其投放到uuid

还有一个可用于生成uuiduuid-ossp的模块。