Postgres 中的 UUID 主键,什么插入性能影响?

UUID Primary Key in Postgres, What Insert Performance Impact?

我想知道在 table 中使用非顺序 UUID 作为主键对性能的影响,这在 PosgreSQL 中会变得非常大。

在为 table 记录使用集群存储的 DBMS 中,假设使用 UUID 会增加插入成本,因为必须从磁盘读取以找到要执行的数据页插入,一旦 table 太大而无法保存在内存中。据我了解,Postgres 不会在插入时维护行集群,因此我想在 Postgres 中使用 UUID PK 不会损害该插入的性能。

但我认为,一旦 table 很大,主键约束创建的索引插入操作就会变得更加昂贵,因为必须不断地从磁盘读取它以更新索引关于插入新数据。而对于顺序键,索引只会在始终在内存中的提示处更新。

假设我正确理解了对索引的性能影响,是否有任何方法可以解决这个问题,或者 UUID 在大型未分区的 table 上根本不是一个好的 PK?

As I understand it, Postgres does not maintain row clustering on inserts

目前正确。很遗憾。

so I imagine that in Postgres using a UUID PK does not hurt the performance of that insert.

由于需要维护PK,并且插入的元组更大,它仍然有性能成本。

  • uuid 的宽度是典型的 32 位整数合成密钥的 4 倍,因此要写入的行要大 12 个字节,您可以将更少的行放入给定数量的 RAM

  • 实现主键的 b 树索引将是 4 倍大(与 32 位键相比),需要更长的搜索时间并需要更多的内存来缓存。它还需要更频繁的页面拆分。

  • 索引内的写入往往是随机的,不会追加到最近访问的热行

is there any way to remedy [the performance impact on the index] or are UUIDs simply not a good PK on a large, un-partitioned table?

如果你需要一个UUID密钥,你需要一个UUID密钥。如果你不需要,你不应该使用它,但是如果你不能依赖合成密钥的中央来源并且没有合适的自然密钥可供使用,它仍然是可行的方法。

除非您可以将写入限制在一个分区,否则分区不会有太大帮助。此外,如果一次只写入一个分区,您将无法在搜索键时有效地使用约束排除,因此在进行查询时您仍然必须在所有分区的索引中搜索键。只有当您的 UUID 构成复合键的一部分并且您可以在复合键的另一部分上进行分区时,我才能看到它很有用。

应该提到的是,如果您在 UUID 列上有 btree 索引并启用 full_page_writes 选项,您将生成更多 WAL。发生这种情况是因为 UUID 随机性——值不是连续的,因此每次插入都可能触及全新的叶索引叶页。您可以在 On the impact of full-page writes 文章中阅读更多内容。