【问题标题】:UUID or SEQUENCE for primary key?主键的 UUID 或 SEQUENCE?
【发布时间】:2021-11-03 16:17:23
【问题描述】:

我来自 MySQL,在 MySQL 中您可以使用 AUTOINCREMENT 作为行的唯一 id 作为主键。

我发现 Postgresql 中没有 AUTOINCREMENT,只有 SEQUENCE 或 UUID。我在某处读到我们可以使用 UUID 作为表的主键。这具有屏蔽其他用户 ID 的额外优势(因为我想构建将 ID 作为参数的 API)。我应该为 Postgresql 使用哪个?

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    PostgreSQL 中的 sequence 与 MySQL 中的 AUTOINCREMENT 完全相同。 sequenceuuid 更有效,因为它是 8 个字节而不是 uuid 的 16 个字节。您可以使用 uuid 作为主键,就像大多数其他数据类型一样。

    但是,我不明白这与屏蔽用户 ID 有何关系。如果您想从其他用户中屏蔽某个用户的 ID,您应该仔细管理表权限和/或使用 - 例如 - md5() 对 ID 进行哈希处理。

    如果您想保护包含用户数据的表免受试图猜测其他 ID 的窥探黑客的攻击,那么uuid 类型是一个很好的选择。包uuid-ossp 有几种口味。版本 4 是最好的选择,因为它有 122 个随机位(其他 6 个用于识别版本)。您可以像这样创建主键:

    id uuid PRIMARY KEY DEFAULT uuid_generate_v4()
    

    然后你就再也不用担心了。


    PostgreSQL 13+

    您现在可以使用内置函数 gen_random_uuid() 获取版本 4 随机 UUID。

    【讨论】:

    • 我不想屏蔽该用户的 ID,只是不想让用户“猜测”其他用户的 ID(例如,该用户的 ID 是 154,而我正在执行 API 请求,可以猜测还有其他用户 ID 为 153 或 155 并窥探不需要访问令牌的 GET 请求)
    • @Justin:我两个都用。将您的主键定义为 serial,并包含一个唯一的 uuid 列以用于 API 调用。
    • 我不确定效率提升是否值得使用主键和备用键的复杂性,尽管任何用于掩盖对未知/未经授权数据的潜在访问模式的目的都是好的。如果密钥空间以可预测(例如顺序)的方式消耗,则任何依赖于人们无法猜测密钥的系统本质上都是不安全的。
    • 我同意@holdenweb。如果您要为 UUID 支付索引成本,不妨将其作为您的 PK。旁注,您可能需要考虑使用 ULIDs 而不是任何符合 RFC 4122 的 UUID,因为 ULID 是按字典顺序排序的,而 UUID 不是。这种排序具有显着的索引优势,因为新 id 总是添加到索引的“末尾”而不是随机添加。
    • 新版本是gen_random_uuid () → uuid。来自官方文档postgresql.org/docs/current/functions-uuid.html
    【解决方案2】:

    您可以使用 UUID 作为表中的主键,因为它是唯一的。但是请记住,与 SEQUENCE 相比,UUID 将占用更多空间。而且他们也不是很快。但是是的,它们肯定是独一无二的,因此可以保证您获得一致的数据。

    您也可以参考:

    【讨论】:

    • 这里链接的关于 UUID 与序列的文章有点奇怪,因为它不止一次说 UUID 是 37 个字符长...
    • 你能量化“不是很快”的说法吗?当然,生成 uuid 会比增加 id 花费更长的时间,但时间上的差异是否足以引起合理的关注?
    • 链接 1 已失效。
    【解决方案3】:

    多年来,我使用 PK 和 FK 作为数字顺序值来开发数据库应用程序。这已经很完美了,但是近年来,在创建云应用程序时,在应用程序之间交换信息并且我们将在我们开发的各种应用程序之间进行集成时,我们意识到在我们的 API 中使用顺序 ID 最终会付出努力。

    在某些应用程序中,我们必须找到要通过 API 调用发送的(目标应用程序的)ID,另一方面,我们的数据库表,在我们所有的应用程序中,除了顺序 PK / FK 列之外,一个 UUID 列,未在 API 调用中使用。在这种情况下,我们决定重写 API 以便使用 UUID 列。

    这解决了一些问题,因为我们的一个桌面应用程序会将其数据迁移到另一个云应用程序,这个云应用程序也使用了 PK / FK 列。在迁移这些数据时,我们必须更改新序列的 PK / FK 的值,因为序列可能会在桌面应用程序的值和云应用程序的值之间发生冲突。考虑到这一点,我们选择将云应用程序 PK/FK 切换为 UUID,因为来自桌面应用程序的数据有一个 UUID 列。

    然后的问题是通过将 INT 列(PK 和 FK)转换为 UUID 列来转换云应用程序表,而不会丢失表信息。这是一项艰巨的任务,但它变得更容易了,因为我最终构建了一个应用程序,使这种变化更容易。应用程序将每个 PK / FK 整数列更改为 UUID,保留数据和关系。有兴趣的可以点击链接:

    https://claytonbonelli.github.io/int_pk2uuid_pk/

    【讨论】:

    • 现有的序列号也可以通过使用可预测的 uuid 生成器转换为 uuid,例如 update x set uuid = uuid_generate_v5(uuid_ns_url(), 'some-namespace/' || id)。因此,可以为每个表添加 uuid 列,用独立的值填充它们,而无需在内存中进行查找/映射,这会使事情变得更快。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 2018-10-29
    • 2021-10-21
    • 2011-05-16
    相关资源
    最近更新 更多