我们目前的PostgreSQL数据库使用GUID作为主键,并将它们存储为文本字段。
对此,我的最初反应是,尝试执行任何类型的最小笛卡尔连接都将成为索引的噩梦,因为需要找到所有匹配记录。但是,也许我的数据库索引知识有限。
我认为我们应该使用UUID,因为这些是以GUID的二进制表示形式存储的,而文本则不是,并且在文本列上获取的索引量是很少的。
更改这些将是一个重大的项目,我在思考是否值得这样做?
我们目前的PostgreSQL数据库使用GUID作为主键,并将它们存储为文本字段。
对此,我的最初反应是,尝试执行任何类型的最小笛卡尔连接都将成为索引的噩梦,因为需要找到所有匹配记录。但是,也许我的数据库索引知识有限。
我认为我们应该使用UUID,因为这些是以GUID的二进制表示形式存储的,而文本则不是,并且在文本列上获取的索引量是很少的。
更改这些将是一个重大的项目,我在思考是否值得这样做?
uuid
。始终如此。根本没有理由考虑使用text
作为替代方案。输入和输出默认都是通过文本表示完成的。类型转换非常廉价。
text
数据类型在RAM和磁盘上需要更多的空间,处理速度较慢,并且容易出错。@khampson's answer提供了大部分的理由。(由于您现有的实现,他得出了不同的结论。)bigint
?bigint
代替。它只占用8个字节,在各个方面都更快。它的范围经常被低估:-9223372036854775808 to +9223372036854775807
那是9.2亿亿亿个正数。换句话说,九百二十三万亿三千七百二十二亿三千零三十六亿多一些。
如果你每秒烧毁100万个身份证(一个极高的数字),你可以持续这样做292471年。然后再持续292471年来处理负数。"数千万或数亿"根本差得太远了。
UUID实际上只是为分布式系统和其他特殊情况设计的。
UUID
类型。 - khampsonuuid
类型。在Postgres中可以使用以下语句:SELECT md5('foo')::uuid
。详情请参见:https://dev59.com/cmsy5IYBdhLWcg3wyxCi#8335376(底部)和https://dba.stackexchange.com/a/115316/3684。 - Erwin Brandstetter正如 @Kevin 提到的那样,确切数据的比较和对比是唯一确定的方法,但从您所描述的情况来看,我不认为这与任何其他情况有什么不同,其中字符串要么是表中的主键,要么是独特索引的一部分。
可以提前说明的是,您的索引可能会更大,因为它们必须存储更大的字符串值,并且从理论上讲,索引的比较需要更长的时间,但如果这样做会很痛苦,我不建议进行过早优化。
根据我的经验,在拥有数十亿行的表格上使用 md5sums 的唯一索引性能非常好。我发现查询的其他方面往往会导致性能问题。例如,当您最终需要查询表格中的大量数据时(例如数十万行),连续扫描就成为更好的选择,因此这就是查询计划器所选择的内容,而这可能需要花费更长的时间。
针对该情况还有其他缓解策略,例如对查询进行分块,然后将结果进行联合 (例如手动模拟在 Hadoop 球中的 Hive 或 Impala 中执行的操作)。
关于您对文本索引的担忧,虽然我确定有些数据集会产生关键分布,从而使性能变差,但 GUID 与 md5sums、sha1 等索引通常表现良好,不需要连续扫描 (除非像上面提到的那样查询整个表格中的大量数据)。
影响索引性能的一个重要因素是有多少唯一值。因此,对于具有大量行的表格的布尔索引不太可能有所帮助,因为它基本上将针对索引中的任何值 (true、false 和潜在的 NULL) 都有大量行冲突。另一方面,GUID 索引可能会有大量没有冲突的值 (理论上定义如此,因为它们是 GUID)。
针对OP的评论进行编辑:所以你是说UUID GUID和Text GUID在索引方面是一样的吗?我们的整个表结构都使用Text字段来存储GUID,但我不确定Postgre是否认为它是GUID。只是一个唯一的字符串。
不完全相同。但是我认为对于这种情况,它们应该具有非常类似的性能,并且我不认为事先优化是值得执行的,特别是考虑到你说要这样做将是一项非常复杂的任务。
如果在特定环境中遇到性能问题,您可以随时稍后更改。但是,正如我之前提到的,如果您遇到这种情况,还有其他事情可能会产生比更改PK数据类型更好的性能。
UUID 是128位数据类型(即16字节),而text的开销为1或4字节,再加上字符串的实际长度。对于GUID,这意味着至少33个字节,但根据使用的编码方式可以有很大的差异。
因此,考虑到这一点,基于文本的UUID的索引肯定会更大,因为值更大,并且比较两个字符串与两个数字值在理论上效率更低,但在这种情况下不太可能产生很大区别,至少在通常情况下不会。
如果要以显着的成本进行事先优化并且可能永远不会需要,则我不会这样做。如果到了那个时候,可以跨越这座桥(尽管我会首先考虑其他查询优化,如上面所述)。
关于Postgres是否知道这个字符串是GUID,它默认情况下肯定不知道。在它看来,它只是一个唯一的字符串。但这对大多数情况来说应该是可以的,例如匹配行等。如果您发现自己需要某些特定要求GUID的行为(例如,一些非等值比较,其中GUID比纯字典排序的结果不同),那么您可以将字符串强制转换为UUID,Postgres会在查询期间将其视为此类值。foo
,您可以执行foo::uuid
将其转换为uuid
。uuid
的模块uuid-ossp。