PostgreSQL使用UUID vs Text作为主键

Sco*_*tie 13 postgresql uuid primary-key

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

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

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

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

Erw*_*ter 13

处理UUID号时,将它们存储为数据类型uuid.总是.甚至没有充分理由认为text是替代方案.无论如何,输入和输出默认通过文本表示完成.演员很便宜.

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

这一切都已被问及,之前已经回答和讨论过.有关dba.SE的相关问题,详细说明如下:

bigint

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

-9223372036854775808 to +9223372036854775807
Run Code Online (Sandbox Code Playgroud)

这是9亿,数百万的正数.数十亿甚至数亿甚至都不是很接近.

IOW,如果你每秒刻录100万个ID(这是一个非常高的数字)你可以继续这样做292471 .然后另外292471年为负数.
UUID实际上只适用于分布式系统和其他特殊情况.

  • @ErwinBrandstetter:我没有得出相同的结论,因为Scottie说他的数据库已经使用文本GUID实现了,并且改变它将是一项非常大的任务.考虑到这些限制,我认为现在改变它将是面对其他优先事项的过早优化.如果从头开始,我肯定会使用原生的`UUID`类型. (6认同)
  • 对于延迟更新的分布式系统来说,所以使用 guid 是有意义的。 (2认同)
  • @Scottie:这是用例,是的。 (2认同)
  • @PirateApp:将 md5 的十六进制表示形式转换为直接键入“uuid”。这适用于 Postgres `SELECT md5('foo')::uuid`。请参阅:/sf/answers/583476351/(在底部)和:https://dba.stackexchange.com/a/115316/3684 (2认同)

kha*_*son 10

正如@Kevin所提到的那样,确切地知道你的确切数据的唯一方法是比较和对比两种方法,但是根据你所描述的,我不明白为什么这会与其他任何字符串的情况不同是表中的主键还是唯一索引的一部分.

可以预先说明你的索引可能会更大,因为它们必须存储更大的字符串值,理论上索引的比较需要更长的时间,但我不提倡过早优化,如果这样做会痛苦.

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

针对这种情况还有其他缓解策略,例如分块查询然后UNION结果(例如,手动模拟将在Hadoop球体中的HiveImpala中完成的事情).

Re:您对文本索引的关注,而我确信在某些情况下,数据集会产生密钥分布,使得它执行非常严重,GUID,就像md5sums,sha1's等一般应该指数很好而且不需要顺序扫描(除非,如上所述,您查询表格的大块区域).

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

编辑以回应OP的评论:

字面意思不一样,没有.但是,我说他们应该在这个特定情况下具有非常相似的性能,我不明白为什么预先优化是值得做的,特别是考虑到你说这样做将是一个非常复杂的任务.

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

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

因此,考虑到这一点,基于文本的UUID的索引肯定会更大,因为值更大,并且比较两个字符串与两个数值在理论上效率较低,但不是可能在这方面产生巨大差异的东西案件,至少不是通常情况.

我不会预先优化这样做将是一个巨大的成本,可能永远不会需要.如果那个时间到来的话,那个桥可以被交叉(虽然我会首先讨论其他查询优化,如上所述).

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

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

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