在 Postgres 10.12 中使用 uuid 作为主键对性能有何影响?(需要规范的答案)

ffx*_*sam 16 postgresql index primary-key postgresql-10

我正处于一个十字路口,我需要决定是否要坚持bigserial作为我的主键,或者更改为uuid(非自动生成\xe2\x80\x94)我的 API 服务器将使用 uuid v4 生成 ID并插入)。

\n

我花了几个小时研究bigserialuuid键,似乎没有人能就其缺点uuid(如果有的话)达成一致。jsonb我的数据库并没有那么复杂:它是一系列具有非常基本关系的表,我通常一次只插入一行,我到处使用一些字段。写入速度/频率只会在一张表上特别高。

\n

我开始研究 UUID 的原因并不是因为我认为我会用完bigint密钥(如果我没记错的话,有 9 千万亿),更多的是从混淆的角度来看。现在我必须在前端对 ID 进行哈希处理,以避免在 URL 中显示用户数据库 ID(例如/things/2732)。使用Hashids,我可以使用类似 的 URL /things/To2jZP13dG。但我认为我可以更进一步,只使用 UUID,它不会提供有关记录数的任何线索。我不喜欢的是,在将 ID 传递到后端并在那里解码之前必须对其进行编码,然后在查询 50-100 个项目的批次以返回给客户端时,必须对所有这些进行批量编码,这会增加额外的工作量在将 ID 返回给客户之前。

\n

支持随机 UUID(uuid v4)的一个论据是:

\n
\n

如果您的主键是递增 ID,则它们在物理上彼此相邻存储。由于许多人正在写入该数据库页面,因此该数据库页面可能会发生争用。随机 ID 通过将写入分散到整个数据库来防止争用

\n
\n

但后来我发现这里有一个矛盾的说法有一个矛盾的说法:

\n
\n

常规随机 UUID 在整个可能值范围内均匀分布。这会导致在将数据插入索引时局部性较差 - 所有索引叶页都同样可能被命中,从而迫使整个索引进入内存。对于小索引来说这没什么问题,但是一旦索引大小超过共享缓冲区(或 RAM),缓存命中率就会迅速下降。

\n
\n

我知道 Heroku 的人们热衷于使用 UUID 作为主键。不管它的价值如何,我根本不打算让 Postgres 自动生成 ID。相反,我的 API 服务器会生成一个 v4 UUID 并将其传递到数据库(这将使我的 API 服务器和前端客户端更加高效,并且不必总是RETURNING id在查询中使用语句)。

\n

INSERT有人对用uuid作主键时语句的真实成本有规范的答案吗?

\n

Lau*_*lbe 14

对此进行基准测试很容易,但INSERTUUID 的性能会更差,因为它们更大且生成速度更慢。

但无论如何,听起来您并不是在构建高性能应用程序(那么您可能不会使用 JSON),因此它可能不会有太大区别。

最后,出于安全原因您希望使用 UUID(我不会在这里讨论)。安全性总是会损害性能和可用性,因此请将其视为您为安全性付出的代价。


J.D*_*.D. 5

Laurenz 所说的是真的,但实际上,当您尝试UUID在谓词(例如JOIN,在WHERE、 和HAVING子句中)中使用这些字段时,我实际上发现了性能上的更可衡量的差异。同样,这取决于谓词所针对的表之间的数据量,但 16 字节值和另一个 16 字节值之间的比较与 4 字节和 4 字节值之间的比较有些显着不同,例如,如果字段是INT数据类型。但正如劳伦兹所提到的,这是为安全而付出的合理代价。